| #!/usr/bin/env python | |
| # | |
| # | |
| # Licensed to the Apache Software Foundation (ASF) under one | |
| # or more contributor license agreements. See the NOTICE file | |
| # distributed with this work for additional information | |
| # regarding copyright ownership. The ASF licenses this file | |
| # to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance | |
| # with the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, | |
| # software distributed under the License is distributed on an | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| # KIND, either express or implied. See the License for the | |
| # specific language governing permissions and limitations | |
| # under the License. | |
| # | |
| # | |
| ### Repository lock checker. Gets an exclusive lock on the provided | |
| ### repository, then runs db_stat to see if the lock counts have been | |
| ### reset to 0. If not, prints the timestamp of the run and a message | |
| ### about accumulation. | |
| DB_STAT = 'db_stat' | |
| import sys | |
| import os | |
| import os.path | |
| import time | |
| import fcntl | |
| import getopt | |
| try: | |
| my_getopt = getopt.gnu_getopt | |
| except AttributeError: | |
| my_getopt = getopt.getopt | |
| def usage_and_exit(retval): | |
| if retval: | |
| out = sys.stderr | |
| else: | |
| out = sys.stdout | |
| out.write("""Usage: %s [OPTIONS] REPOS-PATH | |
| Options: | |
| --help (-h) : Show this usage message | |
| --non-blocking : Don't wait for a lock that can't be immediately obtained | |
| Obtain an exclusive lock (waiting for one unless --non-blocking is | |
| passed) on REPOS-PATH, then check its lock usage counts. If there is | |
| any accumulation present, report that accumulation to stdout. | |
| """ % (os.path.basename(sys.argv[0]))) | |
| sys.exit(retval) | |
| def main(): | |
| now_time = time.asctime() | |
| repos_path = None | |
| nonblocking = 0 | |
| # Parse the options. | |
| optlist, args = my_getopt(sys.argv[1:], "h", ['non-blocking', 'help']) | |
| for opt, arg in optlist: | |
| if opt == '--help' or opt == '-h': | |
| usage_and_exit(0) | |
| if opt == '--non-blocking': | |
| nonblocking = 1 | |
| else: | |
| usage_and_exit(1) | |
| # We need at least a path to work with, here. | |
| argc = len(args) | |
| if argc < 1 or argc > 1: | |
| usage_and_exit(1) | |
| repos_path = args[0] | |
| fd = open(os.path.join(repos_path, 'locks', 'db.lock'), 'a') | |
| try: | |
| # Get an exclusive lock on the repository lock file, but maybe | |
| # don't wait for it. | |
| try: | |
| mode = fcntl.LOCK_EX | |
| if nonblocking: | |
| mode = mode | fcntl.LOCK_NB | |
| fcntl.lockf(fd, mode) | |
| except IOError: | |
| sys.stderr.write("Error obtaining exclusive lock.\n") | |
| sys.exit(1) | |
| # Grab the db_stat results. | |
| lines = os.popen('%s -ch %s' % (DB_STAT, os.path.join(repos_path, 'db'))) | |
| log_lines = [] | |
| for line in lines: | |
| pieces = line.split('\t') | |
| if (pieces[1].find('current lock') != -1) and (int(pieces[0]) > 0): | |
| log = '' | |
| if not len(log_lines): | |
| log = log + "[%s] Lock accumulation for '%s'\n" \ | |
| % (now_time, repos_path) | |
| log = log + ' ' * 27 | |
| log = log + "%s\t%s" % (pieces[0], pieces[1]) | |
| log_lines.append(log) | |
| if len(log_lines): | |
| sys.stdout.write(''.join(log_lines)) | |
| finally: | |
| # Unlock the lockfile | |
| fcntl.lockf(fd, fcntl.LOCK_UN) | |
| fd.close() | |
| if __name__ == "__main__": | |
| main() |