summaryrefslogtreecommitdiff
path: root/tests/test-concurrency.py
blob: 99b7436bde84b87f556104322984d8fcc69945f6 (plain)
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
#!/usr/bin/env python3
#
# Copyright (C) 2017 Colin Walters <walters@verbum.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <https://www.gnu.org/licenses/>.

from __future__ import division
from __future__ import print_function
import os
import sys
import shutil
import subprocess
from multiprocessing import cpu_count

def fatal(msg):
    sys.stderr.write(msg)
    sys.stderr.write('\n')
    sys.exit(1)

# Create 20 files with content based on @dname + a serial, basically to have
# different files with different checksums.
def mktree(dname, serial=0):
    print('Creating tree', dname, file=sys.stderr)
    os.mkdir(dname, 0o755)
    for v in range(20):
        with open('{}/{}'.format(dname, v), 'w') as f:
            f.write('{} {} {}\n'.format(dname, serial, v))

subprocess.check_call(['ostree', '--repo=repo', 'init', '--mode=bare'])
with open('repo/config', 'a') as f:
    # like the bit in libtest, but let's do it unconditionally since
    # it's simpler, and we don't need xattr coverage for this
    f.write('disable-xattrs=true\n')

    # Make any locking errors fail quickly instead of blocking the test
    # for 30 seconds.
    f.write('lock-timeout-secs=5\n')

def commit(v):
    tdir='tree{}'.format(v)
    cmd = ['ostree', '--repo=repo', 'commit', '--fsync=0', '-b', tdir, '--tree=dir='+tdir]
    proc = subprocess.Popen(cmd)
    print('PID {}'.format(proc.pid), *cmd, file=sys.stderr)
    return proc
def prune():
    cmd = ['ostree', '--repo=repo', 'prune', '--refs-only']
    proc = subprocess.Popen(cmd)
    print('PID {}:'.format(proc.pid), *cmd, file=sys.stderr)
    return proc

def wait_check(proc):
    pid = proc.pid
    proc.wait()
    if proc.returncode != 0:
        sys.stderr.write("process {} exited with code {}\n".format(proc.pid, proc.returncode))
        return False
    else:
        sys.stderr.write('PID {} exited OK\n'.format(pid))
        return True

print("1..2")

def run(n_committers, n_pruners):
    # The number of committers needs to be even since we only create half as
    # many trees
    n_committers += n_committers % 2

    committers = set()
    pruners = set()

    print('n_committers', n_committers, 'n_pruners', n_pruners, file=sys.stderr)
    n_trees = n_committers // 2
    for v in range(n_trees):
        mktree('tree{}'.format(v))

    for v in range(n_committers):
        committers.add(commit(v // 2))
    for v in range(n_pruners):
        pruners.add(prune())

    failed = False
    for committer in committers:
        if not wait_check(committer):
            failed = True
    for pruner in pruners:
        if not wait_check(pruner):
            failed = True
    if failed:
        fatal('A child process exited abnormally')

    for v in range(n_trees):
        shutil.rmtree('tree{}'.format(v))

# No concurrent pruning
run(cpu_count() // 2 + 2, 0)
print("ok no concurrent prunes")

run(cpu_count() // 2 + 4, 3)
print("ok concurrent prunes")