blob: 710bf48dbec8c24946990465df12bbef00b0f07e [file] [log] [blame]
#!/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()