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_txn14.py
30#   Transactions: commits and rollbacks
31#
32
33import fnmatch, os, shutil, time
34from suite_subprocess import suite_subprocess
35from wtscenario import make_scenarios
36import wttest
37
38class test_txn14(wttest.WiredTigerTestCase, suite_subprocess):
39    t1 = 'table:test_txn14_1'
40    create_params = 'key_format=i,value_format=i'
41    entries = 10000
42    extra_entries = 5
43    conn_config = 'log=(archive=false,enabled,file_max=100K)'
44
45    sync_list = [
46        ('write', dict(sync='off')),
47        ('sync', dict(sync='on')),
48        ('bg', dict(sync='background')),
49    ]
50    scenarios = make_scenarios(sync_list)
51
52    def simulate_crash_restart(self, olddir, newdir):
53        ''' Simulate a crash from olddir and restart in newdir. '''
54        # with the connection still open, copy files to new directory
55        shutil.rmtree(newdir, ignore_errors=True)
56        os.mkdir(newdir)
57        for fname in os.listdir(olddir):
58            fullname = os.path.join(olddir, fname)
59            # Skip lock file on Windows since it is locked
60            if os.path.isfile(fullname) and \
61                "WiredTiger.lock" not in fullname and \
62                "Tmplog" not in fullname and \
63                "Preplog" not in fullname:
64                shutil.copy(fullname, newdir)
65        #
66        # close the original connection and open to new directory
67        # NOTE:  This really cannot test the difference between the
68        # write-no-sync (off) version of log_flush and the sync
69        # version since we're not crashing the system itself.
70        #
71        self.close_conn()
72        self.conn = self.setUpConnectionOpen(newdir)
73        self.session = self.setUpSessionOpen(self.conn)
74
75    def test_log_flush(self):
76        # Here's the strategy:
77        #    - Create a table.
78        #    - Insert data into table.
79        #    - Call log_flush.
80        #    - Simulate a crash and restart
81        #    - Make recovery run.
82        #    - Confirm flushed data is in the table.
83        #
84        self.session.create(self.t1, self.create_params)
85        c = self.session.open_cursor(self.t1, None, None)
86        for i in range(self.entries):
87            c[i] = i + 1
88        cfgarg='sync=%s' % self.sync
89        self.pr('cfgarg ' + cfgarg)
90        self.session.log_flush(cfgarg)
91        for i in range(self.extra_entries):
92            c[i+self.entries] = i + self.entries + 1
93        c.close()
94        self.session.log_flush(cfgarg)
95        if self.sync == 'background':
96            # If doing a background flush, wait 30 seconds. I have seen an
97            # individual log file's fsync take more than a second on some
98            # systems, and we've seen timeouts at 10 seconds on systems
99            # with slow I/O. So give it time to flush perhaps a few files.
100            self.session.transaction_sync('timeout_ms=30000')
101        self.simulate_crash_restart(".", "RESTART")
102        c = self.session.open_cursor(self.t1, None, None)
103        i = 0
104        for key, value in c:
105            self.assertEqual(i, key)
106            self.assertEqual(i+1, value)
107            i += 1
108        all = self.entries + self.extra_entries
109        self.assertEqual(i, all)
110        c.close()
111
112if __name__ == '__main__':
113    wttest.run()
114