Add a file based driver

Change-Id: Ie299a8a27045526c27907cdf97b8a240325d908c
This commit is contained in:
Julien Danjou
2015-01-12 13:35:04 +01:00
parent 26c39acd31
commit 405dfec672
4 changed files with 138 additions and 1 deletions

View File

@@ -24,6 +24,10 @@ API, some of them have different properties:
some basic group primitives (with huge limitations). The lock can only be some basic group primitives (with huge limitations). The lock can only be
distributed locally to a computer processes. distributed locally to a computer processes.
* `file` is based on file and only implements a lock based on POSIX or Window
file locking for now. The lock can only be distributed locally to a computer
processes.
* `zake`_ is a driver using a fake implementation of ZooKeeper and can be * `zake`_ is a driver using a fake implementation of ZooKeeper and can be
used to use Tooz in your unit tests suite for example. used to use Tooz in your unit tests suite for example.

View File

@@ -32,6 +32,7 @@ tooz.backends =
redis = tooz.drivers.redis:RedisDriver redis = tooz.drivers.redis:RedisDriver
postgresql = tooz.drivers.pgsql:PostgresDriver postgresql = tooz.drivers.pgsql:PostgresDriver
mysql = tooz.drivers.mysql:MySQLDriver mysql = tooz.drivers.mysql:MySQLDriver
file = tooz.drivers.file:FileDriver
[build_sphinx] [build_sphinx]
all_files = 1 all_files = 1

131
tooz/drivers/file.py Normal file
View File

@@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
#
# Copyright © 2015 eNovance
#
# Licensed 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.
import errno
import os
import weakref
import tooz
from tooz import coordination
from tooz.drivers import _retry
from tooz import locking
class FileLock(locking.Lock):
"""A file based lock."""
def __init__(self, path):
super(FileLock, self).__init__(path)
self.acquired = False
def acquire(self, blocking=True):
self.lockfile = open(self.name, 'a')
@_retry.retry(stop_max_delay=blocking)
def _lock():
# NOTE(jd) If the same process try to grab the lock, the call to
# self.lock() will succeed, so we track internally if the process
# already has the lock.
if self.acquired is True:
if blocking:
raise _retry.Retry
return False
try:
self.lock()
except IOError as e:
if e.errno in (errno.EACCESS, errno.EAGAIN):
if blocking:
raise _retry.Retry
return False
else:
self.acquired = True
return True
return _lock()
def release(self):
self.unlock()
self.lockfile.close()
self.acquired = False
def lock(self):
raise NotImplementedError
def unlock(self):
raise NotImplementedError
class WindowsFileLock(FileLock):
def lock(self):
msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1)
def unlock(self):
msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1)
class PosixFileLock(FileLock):
def lock(self):
fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
def unlock(self):
fcntl.lockf(self.lockfile, fcntl.LOCK_UN)
if os.name == 'nt':
import msvcrt
LockClass = WindowsFileLock
else:
import fcntl
LockClass = PosixFileLock
class FileDriver(coordination.CoordinationDriver):
"""A file based driver."""
LOCKS = weakref.WeakValueDictionary()
def __init__(self, member_id, parsed_url, options):
"""Initialize the file driver."""
super(FileDriver, self).__init__()
self._lockdir = parsed_url.path
def get_lock(self, name):
path = os.path.abspath(os.path.join(self._lockdir, name.decode()))
lock = LockClass(path)
return self.LOCKS.setdefault(path, lock)
@staticmethod
def watch_join_group(group_id, callback):
raise tooz.NotImplemented
@staticmethod
def unwatch_join_group(group_id, callback):
raise tooz.NotImplemented
@staticmethod
def watch_leave_group(group_id, callback):
raise tooz.NotImplemented
@staticmethod
def unwatch_leave_group(group_id, callback):
raise tooz.NotImplemented
@staticmethod
def watch_elected_as_leader(group_id, callback):
raise tooz.NotImplemented
@staticmethod
def unwatch_elected_as_leader(group_id, callback):
raise tooz.NotImplemented

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright © 2013-2014 eNovance Inc. All Rights Reserved. # Copyright © 2013-2015 eNovance Inc. All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain # not use this file except in compliance with the License. You may obtain
@@ -36,6 +36,7 @@ class TestAPI(testscenarios.TestWithScenarios,
'bad_url': 'memcached://localhost:1', 'bad_url': 'memcached://localhost:1',
'timeout_capable': True}), 'timeout_capable': True}),
('ipc', {'url': 'ipc://'}), ('ipc', {'url': 'ipc://'}),
('file', {'url': 'file:///tmp'}),
('redis', {'url': os.getenv("TOOZ_TEST_REDIS_URL"), ('redis', {'url': os.getenv("TOOZ_TEST_REDIS_URL"),
'bad_url': 'redis://localhost:1', 'bad_url': 'redis://localhost:1',
'timeout_capable': True}), 'timeout_capable': True}),