File: replicationtest2.py

package info (click to toggle)
xapian-bindings 1.2.3-3
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 10,144 kB
  • ctags: 13,789
  • sloc: cpp: 139,078; sh: 10,401; python: 5,530; cs: 5,394; java: 5,243; php: 2,029; makefile: 783; ruby: 452; tcl: 250
file content (177 lines) | stat: -rw-r--r-- 6,548 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# Tests of Python-specific parts of the xapian bindings.
#
# Copyright (C) 2007,2008 Lemur Consulting Ltd
# Copyright (C) 2008,2009 Olly Betts
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
# USA

import os
import shutil
import subprocess
import sys
import time
import xapian

from testsuite import *

def set_master(masterpath, srcpath):
    # Take a copy of the source, to make modifications to.
    if os.path.exists(masterpath + "_"):
        shutil.rmtree(masterpath + "_")
    shutil.copytree(srcpath, masterpath + "_")

    # Set a new uuid on the copy.
    xapian.WritableDatabase(masterpath + "__", xapian.DB_CREATE_OR_OVERWRITE)
    os.unlink(os.path.join(masterpath + "_", "iamchert"))
    os.rename(os.path.join(masterpath + "__", "iamchert"),
              os.path.join(masterpath + "_", "iamchert"))
    shutil.rmtree(masterpath + "__")

    # Replace the current master with the copy of the source.
    # Note that this isn't an atomic replace, so we'll sometimes get errors
    # such as "NetworkError: Unable to fully synchronise: Can't open database:
    # Cannot open tables at consistent revisions" - the replication protocol
    # should recover happily from this, though.
    if os.path.exists(masterpath):
        os.rename(masterpath, masterpath + "__")
    os.rename(masterpath + '_', masterpath)
    if os.path.exists(masterpath + "__"):
        shutil.rmtree(masterpath + "__")

def test_replication_concurrency():
    """Test concurrent replication and modification

    """

    builddir = os.environ['abs_builddir']
    dbsdir = os.path.join(builddir, 'dbs_replication')
    if not os.path.isdir(dbsdir):
        os.makedirs(dbsdir)

    masterpath = os.path.join(dbsdir, 'master')
    firstpath = os.path.join(dbsdir, 'first')
    secondpath = os.path.join(dbsdir, 'second')
    slavepath = os.path.join(dbsdir, 'slave')
    if os.path.isdir(masterpath):
        shutil.rmtree(masterpath)
    if os.path.isdir(slavepath):
        shutil.rmtree(slavepath)
    port = 7876

    expect_exception(xapian.DatabaseOpeningError,
                     "Couldn't stat '" + dbsdir + "/slave' (No such file or directory)",
                     xapian.Database, slavepath)

    clientp = None
    serverp = subprocess.Popen(('../../xapian-core/bin/xapian-replicate-server',
                                dbsdir,
                                '--port=7876',
                               ),
                              )

    doccount1 = 10000
    doccount2 = 1000

    starttime = time.time()
    if not os.path.isdir(firstpath):
        firstdb = xapian.WritableDatabase(firstpath, xapian.DB_CREATE_OR_OVERWRITE)
        # Make an initial, large database
        print
        print "Building initial database ..."
        for num in xrange(1, doccount1):
            doc=xapian.Document()
            val = 'val%d' % num
            doc.add_value(1, val)
            firstdb.add_document(doc)
            if num % 100000 == 0:
                print "%d documents..." % num
        firstdb.set_metadata('dbname', '1')
        firstdb.commit()
        print "built"

    # The secondary database gets modified during the test, so needs to be
    # cleared now.
    shutil.rmtree(secondpath)
    if not os.path.isdir(secondpath):
        seconddb = xapian.WritableDatabase(secondpath, xapian.DB_CREATE_OR_OVERWRITE)
        # Make second, small database
        print
        print "Building secondary database ..."
        for num in xrange(1, doccount2):
            doc=xapian.Document()
            val = 'val%d' % num
            doc.add_value(1, val)
            seconddb.add_document(doc)
            if num % 100000 == 0:
                print "%d documents..." % num
        seconddb.set_metadata('dbname', '2')
        seconddb.commit()
        print "built"

    if time.time() - starttime < 1:
        time.sleep(1) # Give server time to start

    try:
        set_master(masterpath, firstpath)
        clientp = subprocess.Popen(('../../xapian-core/bin/xapian-replicate',
                                    '--host=127.0.0.1',
                                    '--master=master',
                                    os.path.join(dbsdir, 'slave'),
                                    '--interval=0',
                                    '--port=7876',
                                    '-r 0',
                                   ),
                                  )
        time.sleep(1) # Give client time to start
        expect(xapian.Database(slavepath).get_metadata('dbname'), '1')

        for count in xrange(10):
            # Test that swapping between databases doesn't confuse replication.
            for count2 in xrange(2):
                set_master(masterpath, secondpath)
                time.sleep(0.1)
                set_master(masterpath, firstpath)
                time.sleep(0.1)

            # Test making changes to the database.
            set_master(masterpath, secondpath)
            masterdb = xapian.WritableDatabase(masterpath, xapian.DB_OPEN)
            print "making 100 changes"
            for num in xrange(100):
                masterdb.set_metadata('num%d' % num, str(num + count))
                masterdb.commit()
            print "changes done"
            masterdb.close()

            # Allow time for the replication client to catch up with the
            # changes.
            time.sleep(2)
            expect(xapian.Database(slavepath).get_metadata('dbname'), '2')
            expect(xapian.Database(slavepath).get_metadata('num99'), str(99 + count))

    finally:
        if clientp is not None:
            os.kill(clientp.pid, 9)
            clientp.wait()
        os.kill(serverp.pid, 9)
        serverp.wait()
        #shutil.rmtree(dbsdir)

# Run all tests (ie, callables with names starting "test_").
if not runtests(globals(), sys.argv[1:]):
    sys.exit(1)

# vim:syntax=python:set expandtab: