Statistics
| Branch: | Tag: | Revision:

root / lib / utils / filelock.py @ 178ad717

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 2b3b41df Michael Hanselmann
    return cls(os.fdopen(os.open(filename, os.O_RDWR | os.O_CREAT, 0664), "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)