root / lib / utils / filelock.py @ 463f75a5
History | View | Annotate | Download (5 kB)
1 | 9d1b963f | Michael Hanselmann | #
|
---|---|---|---|
2 | 9d1b963f | Michael Hanselmann | #
|
3 | 9d1b963f | Michael Hanselmann | |
4 | 9d1b963f | Michael Hanselmann | # Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
|
5 | 9d1b963f | Michael Hanselmann | #
|
6 | 9d1b963f | Michael Hanselmann | # This program is free software; you can redistribute it and/or modify
|
7 | 9d1b963f | Michael Hanselmann | # it under the terms of the GNU General Public License as published by
|
8 | 9d1b963f | Michael Hanselmann | # the Free Software Foundation; either version 2 of the License, or
|
9 | 9d1b963f | Michael Hanselmann | # (at your option) any later version.
|
10 | 9d1b963f | Michael Hanselmann | #
|
11 | 9d1b963f | Michael Hanselmann | # This program is distributed in the hope that it will be useful, but
|
12 | 9d1b963f | Michael Hanselmann | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 9d1b963f | Michael Hanselmann | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 9d1b963f | Michael Hanselmann | # General Public License for more details.
|
15 | 9d1b963f | Michael Hanselmann | #
|
16 | 9d1b963f | Michael Hanselmann | # You should have received a copy of the GNU General Public License
|
17 | 9d1b963f | Michael Hanselmann | # along with this program; if not, write to the Free Software
|
18 | 9d1b963f | Michael Hanselmann | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 9d1b963f | Michael Hanselmann | # 02110-1301, USA.
|
20 | 9d1b963f | Michael Hanselmann | |
21 | 9d1b963f | Michael Hanselmann | """Utility functions for file-based locks.
|
22 | 9d1b963f | Michael Hanselmann |
|
23 | 9d1b963f | Michael Hanselmann | """
|
24 | 9d1b963f | Michael Hanselmann | |
25 | 9d1b963f | Michael Hanselmann | import fcntl |
26 | 9d1b963f | Michael Hanselmann | import errno |
27 | 9d1b963f | Michael Hanselmann | import os |
28 | 9d1b963f | Michael Hanselmann | import logging |
29 | 9d1b963f | Michael Hanselmann | |
30 | 9d1b963f | Michael Hanselmann | from ganeti import errors |
31 | 9d1b963f | Michael Hanselmann | from ganeti.utils import retry |
32 | 9d1b963f | Michael Hanselmann | |
33 | 9d1b963f | Michael Hanselmann | |
34 | 9d1b963f | Michael Hanselmann | def LockFile(fd): |
35 | 9d1b963f | Michael Hanselmann | """Locks a file using POSIX locks.
|
36 | 9d1b963f | Michael Hanselmann |
|
37 | 9d1b963f | Michael Hanselmann | @type fd: int
|
38 | 9d1b963f | Michael Hanselmann | @param fd: the file descriptor we need to lock
|
39 | 9d1b963f | Michael Hanselmann |
|
40 | 9d1b963f | Michael Hanselmann | """
|
41 | 9d1b963f | Michael Hanselmann | try:
|
42 | 9d1b963f | Michael Hanselmann | fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) |
43 | 9d1b963f | Michael Hanselmann | except IOError, err: |
44 | 9d1b963f | Michael Hanselmann | if err.errno == errno.EAGAIN:
|
45 | 9d1b963f | Michael Hanselmann | raise errors.LockError("File already locked") |
46 | 9d1b963f | Michael Hanselmann | raise
|
47 | 9d1b963f | Michael Hanselmann | |
48 | 9d1b963f | Michael Hanselmann | |
49 | 9d1b963f | Michael Hanselmann | class FileLock(object): |
50 | 9d1b963f | Michael Hanselmann | """Utility class for file locks.
|
51 | 9d1b963f | Michael Hanselmann |
|
52 | 9d1b963f | Michael Hanselmann | """
|
53 | 9d1b963f | Michael Hanselmann | def __init__(self, fd, filename): |
54 | 9d1b963f | Michael Hanselmann | """Constructor for FileLock.
|
55 | 9d1b963f | Michael Hanselmann |
|
56 | 9d1b963f | Michael Hanselmann | @type fd: file
|
57 | 9d1b963f | Michael Hanselmann | @param fd: File object
|
58 | 9d1b963f | Michael Hanselmann | @type filename: str
|
59 | 9d1b963f | Michael Hanselmann | @param filename: Path of the file opened at I{fd}
|
60 | 9d1b963f | Michael Hanselmann |
|
61 | 9d1b963f | Michael Hanselmann | """
|
62 | 9d1b963f | Michael Hanselmann | self.fd = fd
|
63 | 9d1b963f | Michael Hanselmann | self.filename = filename
|
64 | 9d1b963f | Michael Hanselmann | |
65 | 9d1b963f | Michael Hanselmann | @classmethod
|
66 | 9d1b963f | Michael Hanselmann | def Open(cls, filename): |
67 | 9d1b963f | Michael Hanselmann | """Creates and opens a file to be used as a file-based lock.
|
68 | 9d1b963f | Michael Hanselmann |
|
69 | 9d1b963f | Michael Hanselmann | @type filename: string
|
70 | 9d1b963f | Michael Hanselmann | @param filename: path to the file to be locked
|
71 | 9d1b963f | Michael Hanselmann |
|
72 | 9d1b963f | Michael Hanselmann | """
|
73 | 9d1b963f | Michael Hanselmann | # Using "os.open" is necessary to allow both opening existing file
|
74 | 9d1b963f | Michael Hanselmann | # read/write and creating if not existing. Vanilla "open" will truncate an
|
75 | 9d1b963f | Michael Hanselmann | # existing file -or- allow creating if not existing.
|
76 | 9d1b963f | Michael Hanselmann | return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT), "w+"), |
77 | 9d1b963f | Michael Hanselmann | filename) |
78 | 9d1b963f | Michael Hanselmann | |
79 | 9d1b963f | Michael Hanselmann | def __del__(self): |
80 | 9d1b963f | Michael Hanselmann | self.Close()
|
81 | 9d1b963f | Michael Hanselmann | |
82 | 9d1b963f | Michael Hanselmann | def Close(self): |
83 | 9d1b963f | Michael Hanselmann | """Close the file and release the lock.
|
84 | 9d1b963f | Michael Hanselmann |
|
85 | 9d1b963f | Michael Hanselmann | """
|
86 | 9d1b963f | Michael Hanselmann | if hasattr(self, "fd") and self.fd: |
87 | 9d1b963f | Michael Hanselmann | self.fd.close()
|
88 | 9d1b963f | Michael Hanselmann | self.fd = None |
89 | 9d1b963f | Michael Hanselmann | |
90 | 9d1b963f | Michael Hanselmann | def _flock(self, flag, blocking, timeout, errmsg): |
91 | 9d1b963f | Michael Hanselmann | """Wrapper for fcntl.flock.
|
92 | 9d1b963f | Michael Hanselmann |
|
93 | 9d1b963f | Michael Hanselmann | @type flag: int
|
94 | 9d1b963f | Michael Hanselmann | @param flag: operation flag
|
95 | 9d1b963f | Michael Hanselmann | @type blocking: bool
|
96 | 9d1b963f | Michael Hanselmann | @param blocking: whether the operation should be done in blocking mode.
|
97 | 9d1b963f | Michael Hanselmann | @type timeout: None or float
|
98 | 9d1b963f | Michael Hanselmann | @param timeout: for how long the operation should be retried (implies
|
99 | 9d1b963f | Michael Hanselmann | non-blocking mode).
|
100 | 9d1b963f | Michael Hanselmann | @type errmsg: string
|
101 | 9d1b963f | Michael Hanselmann | @param errmsg: error message in case operation fails.
|
102 | 9d1b963f | Michael Hanselmann |
|
103 | 9d1b963f | Michael Hanselmann | """
|
104 | 9d1b963f | Michael Hanselmann | assert self.fd, "Lock was closed" |
105 | 9d1b963f | Michael Hanselmann | assert timeout is None or timeout >= 0, \ |
106 | 9d1b963f | Michael Hanselmann | "If specified, timeout must be positive"
|
107 | 9d1b963f | Michael Hanselmann | assert not (flag & fcntl.LOCK_NB), "LOCK_NB must not be set" |
108 | 9d1b963f | Michael Hanselmann | |
109 | 9d1b963f | Michael Hanselmann | # When a timeout is used, LOCK_NB must always be set
|
110 | 9d1b963f | Michael Hanselmann | if not (timeout is None and blocking): |
111 | 9d1b963f | Michael Hanselmann | flag |= fcntl.LOCK_NB |
112 | 9d1b963f | Michael Hanselmann | |
113 | 9d1b963f | Michael Hanselmann | if timeout is None: |
114 | 9d1b963f | Michael Hanselmann | self._Lock(self.fd, flag, timeout) |
115 | 9d1b963f | Michael Hanselmann | else:
|
116 | 9d1b963f | Michael Hanselmann | try:
|
117 | 9d1b963f | Michael Hanselmann | retry.Retry(self._Lock, (0.1, 1.2, 1.0), timeout, |
118 | 9d1b963f | Michael Hanselmann | args=(self.fd, flag, timeout))
|
119 | 9d1b963f | Michael Hanselmann | except retry.RetryTimeout:
|
120 | 9d1b963f | Michael Hanselmann | raise errors.LockError(errmsg)
|
121 | 9d1b963f | Michael Hanselmann | |
122 | 9d1b963f | Michael Hanselmann | @staticmethod
|
123 | 9d1b963f | Michael Hanselmann | def _Lock(fd, flag, timeout): |
124 | 9d1b963f | Michael Hanselmann | try:
|
125 | 9d1b963f | Michael Hanselmann | fcntl.flock(fd, flag) |
126 | 9d1b963f | Michael Hanselmann | except IOError, err: |
127 | 9d1b963f | Michael Hanselmann | if timeout is not None and err.errno == errno.EAGAIN: |
128 | 9d1b963f | Michael Hanselmann | raise retry.RetryAgain()
|
129 | 9d1b963f | Michael Hanselmann | |
130 | 9d1b963f | Michael Hanselmann | logging.exception("fcntl.flock failed")
|
131 | 9d1b963f | Michael Hanselmann | raise
|
132 | 9d1b963f | Michael Hanselmann | |
133 | 9d1b963f | Michael Hanselmann | def Exclusive(self, blocking=False, timeout=None): |
134 | 9d1b963f | Michael Hanselmann | """Locks the file in exclusive mode.
|
135 | 9d1b963f | Michael Hanselmann |
|
136 | 9d1b963f | Michael Hanselmann | @type blocking: boolean
|
137 | 9d1b963f | Michael Hanselmann | @param blocking: whether to block and wait until we
|
138 | 9d1b963f | Michael Hanselmann | can lock the file or return immediately
|
139 | 9d1b963f | Michael Hanselmann | @type timeout: int or None
|
140 | 9d1b963f | Michael Hanselmann | @param timeout: if not None, the duration to wait for the lock
|
141 | 9d1b963f | Michael Hanselmann | (in blocking mode)
|
142 | 9d1b963f | Michael Hanselmann |
|
143 | 9d1b963f | Michael Hanselmann | """
|
144 | 9d1b963f | Michael Hanselmann | self._flock(fcntl.LOCK_EX, blocking, timeout,
|
145 | 9d1b963f | Michael Hanselmann | "Failed to lock %s in exclusive mode" % self.filename) |
146 | 9d1b963f | Michael Hanselmann | |
147 | 9d1b963f | Michael Hanselmann | def Shared(self, blocking=False, timeout=None): |
148 | 9d1b963f | Michael Hanselmann | """Locks the file in shared mode.
|
149 | 9d1b963f | Michael Hanselmann |
|
150 | 9d1b963f | Michael Hanselmann | @type blocking: boolean
|
151 | 9d1b963f | Michael Hanselmann | @param blocking: whether to block and wait until we
|
152 | 9d1b963f | Michael Hanselmann | can lock the file or return immediately
|
153 | 9d1b963f | Michael Hanselmann | @type timeout: int or None
|
154 | 9d1b963f | Michael Hanselmann | @param timeout: if not None, the duration to wait for the lock
|
155 | 9d1b963f | Michael Hanselmann | (in blocking mode)
|
156 | 9d1b963f | Michael Hanselmann |
|
157 | 9d1b963f | Michael Hanselmann | """
|
158 | 9d1b963f | Michael Hanselmann | self._flock(fcntl.LOCK_SH, blocking, timeout,
|
159 | 9d1b963f | Michael Hanselmann | "Failed to lock %s in shared mode" % self.filename) |
160 | 9d1b963f | Michael Hanselmann | |
161 | 9d1b963f | Michael Hanselmann | def Unlock(self, blocking=True, timeout=None): |
162 | 9d1b963f | Michael Hanselmann | """Unlocks the file.
|
163 | 9d1b963f | Michael Hanselmann |
|
164 | 9d1b963f | Michael Hanselmann | According to C{flock(2)}, unlocking can also be a nonblocking
|
165 | 9d1b963f | Michael Hanselmann | operation::
|
166 | 9d1b963f | Michael Hanselmann |
|
167 | 9d1b963f | Michael Hanselmann | To make a non-blocking request, include LOCK_NB with any of the above
|
168 | 9d1b963f | Michael Hanselmann | operations.
|
169 | 9d1b963f | Michael Hanselmann |
|
170 | 9d1b963f | Michael Hanselmann | @type blocking: boolean
|
171 | 9d1b963f | Michael Hanselmann | @param blocking: whether to block and wait until we
|
172 | 9d1b963f | Michael Hanselmann | can lock the file or return immediately
|
173 | 9d1b963f | Michael Hanselmann | @type timeout: int or None
|
174 | 9d1b963f | Michael Hanselmann | @param timeout: if not None, the duration to wait for the lock
|
175 | 9d1b963f | Michael Hanselmann | (in blocking mode)
|
176 | 9d1b963f | Michael Hanselmann |
|
177 | 9d1b963f | Michael Hanselmann | """
|
178 | 9d1b963f | Michael Hanselmann | self._flock(fcntl.LOCK_UN, blocking, timeout,
|
179 | 9d1b963f | Michael Hanselmann | "Failed to unlock %s" % self.filename) |