Skip to content

Commit 47b617f

Browse files
authored
Merge pull request #6 from timvaillancourt/lock_file
Lock file feature
2 parents 8180815 + 494f9ae commit 47b617f

File tree

4 files changed

+51
-0
lines changed

4 files changed

+51
-0
lines changed

MongoBackup/Backup.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from signal import signal, SIGINT, SIGTERM
99
from time import time
1010

11+
from Common import Lock
1112
from DB import DB
1213
from ShardingHandler import ShardingHandler
1314
from Mongodumper import Mongodumper
@@ -62,6 +63,7 @@ def __init__(self, options):
6263
self.backup_duration = None
6364
self.end_time = None
6465

66+
self._lock = None
6567
self.log_level = logging.INFO
6668
self.start_time = time()
6769
self.oplog_threads = []
@@ -72,6 +74,10 @@ def __init__(self, options):
7274
for option in vars(options):
7375
setattr(self, option, getattr(options, option))
7476

77+
# Set default lock file:
78+
if not self.lock_file:
79+
self.lock_file = '/tmp/%s.lock' % self.program_name
80+
7581
# Setup logging
7682
if self.verbose:
7783
self.log_level = logging.DEBUG
@@ -137,14 +143,24 @@ def cleanup_and_exit(self, code, frame):
137143
self.backup_name
138144
))
139145

146+
if self._lock:
147+
self._lock.release()
148+
140149
logging.info("Cleanup complete. Exiting")
150+
141151
sys.exit(1)
142152

143153
def exception(self, error_message):
144154
logging.exception(error_message)
145155
return self.cleanup_and_exit(None, None)
146156

147157
def run(self):
158+
try:
159+
self._lock = Lock(self.lock_file)
160+
except Exception, e:
161+
logging.fatal("Could not acquire lock! Is another %s process running? Exiting" % self.program_name)
162+
sys.exit(1)
163+
148164
if not self.is_mongos:
149165
logging.info("Starting backup of %s:%s in replset mode" % (self.host, self.port))
150166

@@ -284,4 +300,6 @@ def run(self):
284300
except Exception, e:
285301
self.exception("Problem running NSCA notifier! Error: %s" % e)
286302

303+
self._lock.release()
304+
287305
logging.info("Backup completed in %s sec" % self.backup_duration)

MongoBackup/Common/Lock.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import os
2+
import logging
3+
4+
from fcntl import flock, LOCK_EX, LOCK_NB
5+
6+
7+
class Lock:
8+
def __init__(self, lock_file):
9+
self.lock_file = lock_file
10+
11+
self._lock = None
12+
self.acquire()
13+
14+
def acquire(self):
15+
try:
16+
self._lock = open(self.lock_file, "w")
17+
flock(self._lock, LOCK_EX | LOCK_NB)
18+
logging.debug("Acquired exclusive lock on file: %s" % self.lock_file)
19+
return self._lock
20+
except Exception, e:
21+
logging.debug("Error acquiring lock on file: %s" % self.lock_file)
22+
if self._lock:
23+
self._lock.close()
24+
raise Exception, "Could not acquire lock!", None
25+
26+
def release(self):
27+
if self._lock:
28+
logging.debug("Releasing exclusive lock on file: %s" % self.lock_file)
29+
self._lock.close()
30+
self._lock = None
31+
return os.remove(self.lock_file)

MongoBackup/Common/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
from LocalCommand import LocalCommand
2+
from Lock import Lock

MongoBackup/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def run():
8181
parser.add_option("--no-archive", dest="no_archiver", help="Disable archiving of backups directories post-resolving", action="store_true", default=False)
8282
parser.add_option("--no-archive-gzip", dest="no_archiver_gzip", help="Disable gzip compression of archive files", action="store_true", default=False)
8383
parser.add_option("--lazy", dest="no_oplog_tailer", help="Disable tailing/resolving of clusterwide oplogs. This makes a shard-consistent, not cluster-consistent backup", action="store_true", default=False)
84+
parser.add_option("--lock-file", dest="lock_file", help="Location of lock file (default: /tmp/%s.lock)" % os.path.basename(sys.argv[0]), default="/tmp/%s.lock" % os.path.basename(sys.argv[0]))
8485
parser.set_defaults()
8586

8687
options = handle_options(parser)

0 commit comments

Comments
 (0)