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_txn18.py 30# Transactions: test recovery settings 31# 32 33import fnmatch, os, shutil, time 34from suite_subprocess import suite_subprocess 35import wiredtiger, wttest 36 37class test_txn18(wttest.WiredTigerTestCase, suite_subprocess): 38 t1 = 'table:test_txn18' 39 create_params = 'key_format=i,value_format=i' 40 conn_config = 'log=(archive=false,enabled,file_max=100K),' + \ 41 'transaction_sync=(method=dsync,enabled)' 42 conn_recerror = conn_config + ',log=(recover=error)' 43 conn_recon = conn_config + ',log=(recover=on)' 44 45 def simulate_crash(self, olddir, newdir): 46 ''' Simulate a crash from olddir and restart in newdir. ''' 47 # with the connection still open, copy files to new directory 48 shutil.rmtree(newdir, ignore_errors=True) 49 os.mkdir(newdir) 50 for fname in os.listdir(olddir): 51 fullname = os.path.join(olddir, fname) 52 # Skip lock file on Windows since it is locked 53 if os.path.isfile(fullname) and \ 54 "WiredTiger.lock" not in fullname and \ 55 "Tmplog" not in fullname and \ 56 "Preplog" not in fullname: 57 shutil.copy(fullname, newdir) 58 59 def test_recovery(self): 60 ''' Run the recovery settings ''' 61 62 # Here's the strategy: 63 # - Create a table (t1). 64 # - Insert data into t1. 65 # - Simulate a crash. 66 # - Make recovery run with recovery=error 67 # and make sure it detects an error since recovery is needed 68 # - Make recovery run with recovery=on. 69 # - Do a clean shutdown and restart with recovery=error 70 # and make sure is successful. 71 # 72 # If we aren't tracking file IDs properly, it's possible that 73 # we'd end up apply the log records for t2 to table t1. 74 self.session.create(self.t1, self.create_params) 75 # 76 # Since we're logging, we need to flush out the meta-data file 77 # from the create. 78 self.session.checkpoint() 79 c = self.session.open_cursor(self.t1, None, None) 80 for i in range(10000): 81 c[i] = i + 1 82 c.close() 83 olddir = "." 84 newdir = "RESTART" 85 errdir = "ERROR" 86 self.simulate_crash(olddir, errdir) 87 self.simulate_crash(olddir, newdir) 88 # close the original connection 89 self.close_conn() 90 # Trying to open the error directory with recover=error should return an error. 91 msg = '/recovery must be run/' 92 self.assertRaisesWithMessage(wiredtiger.WiredTigerError, 93 lambda:self.wiredtiger_open(errdir, self.conn_recerror), msg) 94 95 # If recover=error is run on the directory and returns an error, 96 # make sure when we subsequently open with recover=on it properly 97 # recovers all the data. 98 self.assertRaisesWithMessage(wiredtiger.WiredTigerError, 99 lambda:self.wiredtiger_open(newdir, self.conn_recerror), msg) 100 101 # Opening with recover=on should succeed. 102 self.conn = self.wiredtiger_open(newdir, self.conn_recon) 103 # Make sure the data we added originally is there 104 self.session = self.setUpSessionOpen(self.conn) 105 c = self.session.open_cursor(self.t1, None, None) 106 i = 0 107 for key, value in c: 108 self.assertEqual(i, key) 109 self.assertEqual(i+1, value) 110 i += 1 111 self.assertEqual(i, 10000) 112 c.close() 113 self.close_conn() 114 # Reopening with recover=error after a clean shutdown should succeed. 115 self.conn = self.wiredtiger_open(newdir, self.conn_recerror) 116 117if __name__ == '__main__': 118 wttest.run() 119