#!/usr/bin/env python # # Public Domain 2014-present MongoDB, Inc. # Public Domain 2008-2014 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. # # Anyone is free to copy, modify, publish, use, compile, sell, or # distribute this software, either in source code form or as a compiled # binary, for any purpose, commercial or non-commercial, and by any # means. # # In jurisdictions that recognize copyright laws, the author or authors # of this software dedicate any and all copyright interest in the # software to the public domain. We make this dedication for the benefit # of the public at large and to the detriment of our heirs and # successors. We intend this dedication to be an overt act of # relinquishment in perpetuity of all present and future rights to this # software under copyright law. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. import wiredtiger, wttest import os, shutil from helper import compare_files from wtbackup import backup_base from wtdataset import simple_key from wtscenario import make_scenarios # test_backup16.py # Ensure incremental backup doesn't copy unnecessary files. class test_backup16(backup_base): conn_config='cache_size=1G,log=(enabled,file_max=100K)' logmax='100K' # Define the table name and its on-disk file name together. file1='test1.wt' uri1='table:test1' file2='test2.wt' uri2='table:test2' file3='test3.wt' uri3='table:test3' file4='test4.wt' uri4='table:test4' file5='test5.wt' uri5='table:test5' file6='test6.wt' uri6='table:test6' pfx = 'test_backup' # Set the key and value big enough that we modify a few blocks. bigkey = 'Key' * 10 bigval = 'Value' * 10 mult = 1 bkup_id = 1 nops = 10 initial_backup = True def verify_incr_backup(self, expected_file_list): bkup_config = ('incremental=(src_id="ID' + str(self.bkup_id - 1) + '",this_id="ID' + str(self.bkup_id) + '")') bkup_cur = self.session.open_cursor('backup:', None, bkup_config) self.bkup_id += 1 num_files = 0 # Verify the files included in the incremental backup are the ones we expect. # Note that all files will be returned. We're only interested in the ones that # return file information. while True: ret = bkup_cur.next() if ret != 0: break bkup_file = bkup_cur.get_key() if bkup_file.startswith('WiredTiger'): continue incr_config = 'incremental=(file=' + bkup_file + ')' incr_cur = self.session.open_cursor(None, bkup_cur, incr_config) while True: ret = incr_cur.next() # Stop if there is nothing to copy or we're done. if ret != 0: break # Check this file is one we are expecting. self.assertTrue(bkup_file in expected_file_list) num_files += 1 # Ensure that the file we changed has content to copy and the file we didn't # change doesn't have any content to copy. The second value is the number of # bytes to copy for a range return or the file size on a file copy. Either way # it should not be zero. incr_list = incr_cur.get_keys() self.assertNotEqual(incr_list[1], 0) self.assertEqual(ret, wiredtiger.WT_NOTFOUND) incr_cur.close() self.assertEqual(ret, wiredtiger.WT_NOTFOUND) bkup_cur.close() # Ensure that the backup saw all the expected files. self.assertEqual(num_files, len(expected_file_list)) def test_backup16(self): # Create four tables before the first backup. Add data to two of them. self.session.create(self.uri1, 'key_format=S,value_format=S') self.session.create(self.uri2, 'key_format=S,value_format=S') self.session.create(self.uri3, 'key_format=S,value_format=S') self.session.create(self.uri6, 'key_format=S,value_format=S') self.add_data(self.uri1, self.bigkey, self.bigval, True) self.add_data(self.uri2, self.bigkey, self.bigval, True) # Checkpoint and simulate full backup. self.session.checkpoint() config = 'incremental=(enabled,granularity=1M,this_id="ID0")' cursor = self.session.open_cursor('backup:', None, config) cursor.close() # Create new tables, add more data and checkpoint. # Add data to an earlier table and one of the new tables. This now gives us: # 1. An existing table with checkpointed new data and changes to record. # 2. An existing table with old data and no new changes. # 3. An existing table with no data at all but gets new data. # 4. An new table with no data and that will never have new data. # 5. A new table with checkpointed new data. # 6. An existing table with no data and that will never have new data. # # Note that cases 4 and 6 are different. In the case of table 6, since it existed on # disk at the time of the initial full backup it will never appear in the list of files # with any data to copy. In the case of table 4 we will be told to copy the whole file # every time in order to have the new file appear in the backup. # self.session.create(self.uri4, "key_format=S,value_format=S") self.session.create(self.uri5, "key_format=S,value_format=S") self.add_data(self.uri1, self.bigkey, self.bigval, True) self.add_data(self.uri5, self.bigkey, self.bigval, True) self.session.checkpoint() # Validate these three files are included in the incremental. # Both new tables should appear in the incremental and the old table with # new data. files_to_backup = [self.file1, self.file4, self.file5] self.verify_incr_backup(files_to_backup) # Add more data and checkpoint. Earlier old tables without new data should not # appear in the list. The table with no data at all continues to appear in the # list. self.add_data(self.uri3, self.bigkey, self.bigval, True) self.add_data(self.uri5, self.bigkey, self.bigval, True) self.session.checkpoint() # Validate these three files are included in the incremental. files_to_backup = [self.file3, self.file4, self.file5] self.verify_incr_backup(files_to_backup) # Perform one more incremental without changing anything. We should only # see one file, the file that does not have any checkpoint information. files_to_backup = [self.file4] self.verify_incr_backup(files_to_backup) if __name__ == '__main__': wttest.run()