1#!/usr/bin/env python 2# 3# Public Domain 2014-2018 MongoDB, Inc. 4# Public Domain 2008-2014 WiredTiger, Inc. 5# 6# This is free and unencumbered software released into the public domain. 7# 8# Anyone is free to copy, modify, publish, use, compile, sell, or 9# distribute this software, either in source code form or as a compiled 10# binary, for any purpose, commercial or non-commercial, and by any 11# means. 12# 13# In jurisdictions that recognize copyright laws, the author or authors 14# of this software dedicate any and all copyright interest in the 15# software to the public domain. We make this dedication for the benefit 16# of the public at large and to the detriment of our heirs and 17# successors. We intend this dedication to be an overt act of 18# relinquishment in perpetuity of all present and future rights to this 19# software under copyright law. 20# 21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27# OTHER DEALINGS IN THE SOFTWARE. 28# 29# test_backup05.py 30# Test that backups can be performed similar to MongoDB's fsyncLock. 31# We assume writes are not being performed, a checkpoint is done and 32# then we open a backup cursor to prevent log archiving and other file 33# manipulations. Manually copy the directory and verify it. 34# 35 36import fnmatch, os, shutil, time 37from suite_subprocess import suite_subprocess 38from helper import copy_wiredtiger_home 39import wiredtiger, wttest 40 41class test_backup05(wttest.WiredTigerTestCase, suite_subprocess): 42 uri = 'table:test_backup05' 43 emptyuri = 'table:test_empty05' 44 newuri = 'table:test_new05' 45 create_params = 'key_format=i,value_format=i' 46 freq = 5 47 48 def check_manual_backup(self, i, olddir, newdir): 49 ''' Simulate a manual backup from olddir and restart in newdir. ''' 50 self.session.checkpoint() 51 cbkup = self.session.open_cursor('backup:', None, None) 52 53 # With the connection still open, copy files to new directory. 54 # Half the time use an unaligned copy. 55 even = i % (self.freq * 2) == 0 56 aligned = even or os.name == "nt" 57 copy_wiredtiger_home(olddir, newdir, aligned) 58 59 # Half the time try to rename a table and the other half try 60 # to remove a table. They should fail. 61 if not even: 62 self.assertRaises(wiredtiger.WiredTigerError, 63 lambda: self.session.rename( 64 self.emptyuri, self.newuri, None)) 65 else: 66 self.assertRaises(wiredtiger.WiredTigerError, 67 lambda: self.session.drop(self.emptyuri, None)) 68 69 # Now simulate fsyncUnlock by closing the backup cursor. 70 cbkup.close() 71 72 # Once the backup cursor is closed we should be able to perform 73 # schema operations. Test that and then reset the files to their 74 # expected initial names. 75 if not even: 76 self.session.rename(self.emptyuri, self.newuri, None) 77 self.session.drop(self.newuri, None) 78 self.session.create(self.emptyuri, self.create_params) 79 else: 80 self.session.drop(self.emptyuri, None) 81 self.session.create(self.emptyuri, self.create_params) 82 83 # Open the new directory and verify 84 conn = self.setUpConnectionOpen(newdir) 85 session = self.setUpSessionOpen(conn) 86 session.verify(self.uri) 87 conn.close() 88 89 def backup(self): 90 '''Check manual fsyncLock backup strategy''' 91 92 # Here's the strategy: 93 # - update the table 94 # - checkpoint the database 95 # - open a backup cursor 96 # - copy the database directory (live, simulating a crash) 97 # - use copy tree or non-aligned dd 98 # - verify in the copy 99 # - repeat 100 # 101 # If the metadata isn't flushed, eventually the metadata we copy will 102 # be sufficiently out-of-sync with the data file that it won't verify. 103 104 self.session.create(self.emptyuri, self.create_params) 105 self.reopen_conn() 106 107 self.session.create(self.uri, self.create_params) 108 for i in range(100): 109 c = self.session.open_cursor(self.uri) 110 c[i] = i 111 c.close() 112 if i % self.freq == 0: 113 self.check_manual_backup(i, ".", "RESTART") 114 else: 115 self.session.verify(self.uri) 116 117 def test_backup(self): 118 with self.expectedStdoutPattern('recreating metadata'): 119 self.backup() 120 121if __name__ == '__main__': 122 wttest.run() 123