1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | ### Repository lock checker. Gets an exclusive lock on the provided |
---|
4 | ### repository, then runs db_stat to see if the lock counts have been |
---|
5 | ### reset to 0. If not, prints the timestamp of the run and a message |
---|
6 | ### about accumulation. |
---|
7 | |
---|
8 | DB_STAT = 'db_stat' |
---|
9 | |
---|
10 | |
---|
11 | import sys |
---|
12 | import os |
---|
13 | import os.path |
---|
14 | import time |
---|
15 | import fcntl |
---|
16 | import getopt |
---|
17 | try: |
---|
18 | my_getopt = getopt.gnu_getopt |
---|
19 | except AttributeError: |
---|
20 | my_getopt = getopt.getopt |
---|
21 | |
---|
22 | def usage_and_exit(retval): |
---|
23 | if retval: |
---|
24 | out = sys.stderr |
---|
25 | else: |
---|
26 | out = sys.stdout |
---|
27 | out.write("""Usage: %s [OPTIONS] REPOS-PATH |
---|
28 | |
---|
29 | Options: |
---|
30 | --help (-h) : Show this usage message |
---|
31 | --non-blocking : Don't wait for a lock that can't be immediately obtained |
---|
32 | |
---|
33 | Obtain an exclusive lock (waiting for one unless --non-blocking is |
---|
34 | passed) on REPOS-PATH, then check its lock usage counts. If there is |
---|
35 | any accumulation present, report that accumulation to stdout. |
---|
36 | """ % (os.path.basename(sys.argv[0]))) |
---|
37 | sys.exit(retval) |
---|
38 | |
---|
39 | def main(): |
---|
40 | now_time = time.asctime() |
---|
41 | repos_path = None |
---|
42 | nonblocking = 0 |
---|
43 | |
---|
44 | # Parse the options. |
---|
45 | optlist, args = my_getopt(sys.argv[1:], "h", ['non-blocking', 'help']) |
---|
46 | for opt, arg in optlist: |
---|
47 | if opt == '--help' or opt == '-h': |
---|
48 | usage_and_exit(0) |
---|
49 | if opt == '--non-blocking': |
---|
50 | nonblocking = 1 |
---|
51 | else: |
---|
52 | usage_and_exit(1) |
---|
53 | |
---|
54 | # We need at least a path to work with, here. |
---|
55 | argc = len(args) |
---|
56 | if argc < 1 or argc > 1: |
---|
57 | usage_and_exit(1) |
---|
58 | repos_path = args[0] |
---|
59 | |
---|
60 | fd = open(os.path.join(repos_path, 'locks', 'db.lock'), 'a') |
---|
61 | try: |
---|
62 | # Get an exclusive lock on the repository lock file, but maybe |
---|
63 | # don't wait for it. |
---|
64 | try: |
---|
65 | mode = fcntl.LOCK_EX |
---|
66 | if nonblocking: |
---|
67 | mode = mode | fcntl.LOCK_NB |
---|
68 | fcntl.lockf(fd, mode) |
---|
69 | except IOError: |
---|
70 | sys.stderr.write("Error obtaining exclusive lock.\n") |
---|
71 | sys.exit(1) |
---|
72 | |
---|
73 | # Grab the db_stat results. |
---|
74 | lines = os.popen('%s -ch %s' % (DB_STAT, os.path.join(repos_path, 'db'))) |
---|
75 | log_lines = [] |
---|
76 | for line in lines: |
---|
77 | pieces = line.split('\t') |
---|
78 | if (pieces[1].find('current lock') != -1) and (int(pieces[0]) > 0): |
---|
79 | log = '' |
---|
80 | if not len(log_lines): |
---|
81 | log = log + "[%s] Lock accumulation for '%s'\n" \ |
---|
82 | % (now_time, repos_path) |
---|
83 | log = log + ' ' * 27 |
---|
84 | log = log + "%s\t%s" % (pieces[0], pieces[1]) |
---|
85 | log_lines.append(log) |
---|
86 | if len(log_lines): |
---|
87 | sys.stdout.write(''.join(log_lines)) |
---|
88 | finally: |
---|
89 | # Unlock the lockfile |
---|
90 | fcntl.lockf(fd, fcntl.LOCK_UN) |
---|
91 | fd.close() |
---|
92 | |
---|
93 | if __name__ == "__main__": |
---|
94 | main() |
---|