Add programatic introspection of drivers characteristic(s)
Change-Id: Icf187db9ba7d076b1a0f3cc9343acb0eaa1862cb
This commit is contained in:
parent
9f5290ea9c
commit
a3f22fe90c
|
@ -4,13 +4,17 @@ Drivers
|
||||||
|
|
||||||
Tooz is provided with several drivers implementing the provided coordination
|
Tooz is provided with several drivers implementing the provided coordination
|
||||||
API. While all drivers provides the same set of features with respect to the
|
API. While all drivers provides the same set of features with respect to the
|
||||||
API, some of them have different properties.
|
API, some of them have different characteristics:
|
||||||
|
|
||||||
Zookeeper
|
Zookeeper
|
||||||
---------
|
---------
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.zookeeper.KazooDriver`
|
**Driver:** :py:class:`tooz.drivers.zookeeper.KazooDriver`
|
||||||
|
|
||||||
|
**Characteristics:**
|
||||||
|
|
||||||
|
:py:attr:`tooz.drivers.zookeeper.KazooDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``zookeeper`` or ``kazoo``
|
**Entrypoint name:** ``zookeeper`` or ``kazoo``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -21,6 +25,10 @@ resilient towards network partitions for example.
|
||||||
|
|
||||||
**Test driver:** :py:class:`tooz.drivers.zake.ZakeDriver`
|
**Test driver:** :py:class:`tooz.drivers.zake.ZakeDriver`
|
||||||
|
|
||||||
|
**Characteristics:**
|
||||||
|
|
||||||
|
:py:attr:`tooz.drivers.zake.ZakeDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Test driver entrypoint name:** ``zake``
|
**Test driver entrypoint name:** ``zake``
|
||||||
|
|
||||||
Considerations
|
Considerations
|
||||||
|
@ -35,6 +43,10 @@ Memcached
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.memcached.MemcachedDriver`
|
**Driver:** :py:class:`tooz.drivers.memcached.MemcachedDriver`
|
||||||
|
|
||||||
|
**Characteristics:**
|
||||||
|
|
||||||
|
:py:attr:`tooz.drivers.memcached.MemcachedDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``memcached``
|
**Entrypoint name:** ``memcached``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -58,6 +70,10 @@ Redis
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.redis.RedisDriver`
|
**Driver:** :py:class:`tooz.drivers.redis.RedisDriver`
|
||||||
|
|
||||||
|
**Characteristics:**
|
||||||
|
|
||||||
|
:py:attr:`tooz.drivers.redis.RedisDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``redis``
|
**Entrypoint name:** ``redis``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -79,6 +95,8 @@ IPC
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.ipc.IPCDriver`
|
**Driver:** :py:class:`tooz.drivers.ipc.IPCDriver`
|
||||||
|
|
||||||
|
**Characteristics:** :py:attr:`tooz.drivers.ipc.IPCDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``ipc``
|
**Entrypoint name:** ``ipc``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -98,6 +116,8 @@ File
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.file.FileDriver`
|
**Driver:** :py:class:`tooz.drivers.file.FileDriver`
|
||||||
|
|
||||||
|
**Characteristics:** :py:attr:`tooz.drivers.file.FileDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``file``
|
**Entrypoint name:** ``file``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -118,6 +138,10 @@ PostgreSQL
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.pgsql.PostgresDriver`
|
**Driver:** :py:class:`tooz.drivers.pgsql.PostgresDriver`
|
||||||
|
|
||||||
|
**Characteristics:**
|
||||||
|
|
||||||
|
:py:attr:`tooz.drivers.pgsql.PostgresDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``postgresql``
|
**Entrypoint name:** ``postgresql``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -140,6 +164,8 @@ MySQL
|
||||||
|
|
||||||
**Driver:** :py:class:`tooz.drivers.mysql.MySQLDriver`
|
**Driver:** :py:class:`tooz.drivers.mysql.MySQLDriver`
|
||||||
|
|
||||||
|
**Characteristics:** :py:attr:`tooz.drivers.mysql.MySQLDriver.CHARACTERISTICS`
|
||||||
|
|
||||||
**Entrypoint name:** ``mysql``
|
**Entrypoint name:** ``mysql``
|
||||||
|
|
||||||
**Summary:**
|
**Summary:**
|
||||||
|
@ -157,6 +183,11 @@ Considerations
|
||||||
- Does **not** work when MySQL replicates from one server to another (locks
|
- Does **not** work when MySQL replicates from one server to another (locks
|
||||||
are local to the server that they were created from).
|
are local to the server that they were created from).
|
||||||
|
|
||||||
|
Characteristics
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. autoclass:: tooz.coordination.Characteristics
|
||||||
|
|
||||||
.. _advisory locks: http://www.postgresql.org/docs/8.2/interactive/\
|
.. _advisory locks: http://www.postgresql.org/docs/8.2/interactive/\
|
||||||
explicit-locking.html#ADVISORY-LOCKS
|
explicit-locking.html#ADVISORY-LOCKS
|
||||||
.. _get_lock: http://dev.mysql.com/doc/refman/5.5/en/\
|
.. _get_lock: http://dev.mysql.com/doc/refman/5.5/en/\
|
||||||
|
|
|
@ -5,6 +5,7 @@ pbr>=1.6
|
||||||
Babel>=1.3
|
Babel>=1.3
|
||||||
stevedore>=1.5.0 # Apache-2.0
|
stevedore>=1.5.0 # Apache-2.0
|
||||||
six>=1.9.0
|
six>=1.9.0
|
||||||
|
enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3'
|
||||||
iso8601>=0.1.9
|
iso8601>=0.1.9
|
||||||
zake>=0.1.6 # Apache-2.0
|
zake>=0.1.6 # Apache-2.0
|
||||||
jsonschema!=2.5.0,<3.0.0,>=2.0.0
|
jsonschema!=2.5.0,<3.0.0,>=2.0.0
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
import collections
|
import collections
|
||||||
|
import enum
|
||||||
|
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from oslo_utils import netutils
|
from oslo_utils import netutils
|
||||||
|
@ -28,6 +29,74 @@ import tooz
|
||||||
TOOZ_BACKENDS_NAMESPACE = "tooz.backends"
|
TOOZ_BACKENDS_NAMESPACE = "tooz.backends"
|
||||||
|
|
||||||
|
|
||||||
|
class Characteristics(enum.Enum):
|
||||||
|
"""Attempts to describe the characteristic that a driver supports."""
|
||||||
|
|
||||||
|
DISTRIBUTED_ACROSS_THREADS = 'DISTRIBUTED_ACROSS_THREADS'
|
||||||
|
"""Coordinator components when used by multiple **threads** work
|
||||||
|
the same as if those components were only used by a single thread."""
|
||||||
|
|
||||||
|
DISTRIBUTED_ACROSS_PROCESSES = 'DISTRIBUTED_ACROSS_PROCESSES'
|
||||||
|
"""Coordinator components when used by multiple **processes** work
|
||||||
|
the same as if those components were only used by a single thread."""
|
||||||
|
|
||||||
|
DISTRIBUTED_ACROSS_HOSTS = 'DISTRIBUTED_ACROSS_HOSTS'
|
||||||
|
"""Coordinator components when used by multiple **hosts** work
|
||||||
|
the same as if those components were only used by a single thread."""
|
||||||
|
|
||||||
|
LINEARIZABLE = 'LINEARIZABLE'
|
||||||
|
"""The driver has the following properties:
|
||||||
|
|
||||||
|
* Ensures each operation must take place before its
|
||||||
|
completion time.
|
||||||
|
* Any operation invoked subsequently must take place
|
||||||
|
after the invocation and by extension, after the original operation
|
||||||
|
itself.
|
||||||
|
"""
|
||||||
|
|
||||||
|
SEQUENTIAL = 'SEQUENTIAL'
|
||||||
|
"""The driver has the following properties:
|
||||||
|
|
||||||
|
* Operations can take effect before or after completion – but all
|
||||||
|
operations retain the constraint that operations from any given process
|
||||||
|
must take place in that processes order.
|
||||||
|
"""
|
||||||
|
|
||||||
|
CAUSAL = 'CAUSAL'
|
||||||
|
"""The driver has the following properties:
|
||||||
|
|
||||||
|
* Does **not** have to enforce the order of every
|
||||||
|
operation from a process, perhaps, only causally related operations
|
||||||
|
must occur in order.
|
||||||
|
"""
|
||||||
|
|
||||||
|
SERIALIZABLE = 'SERIALIZABLE'
|
||||||
|
"""The driver has the following properties:
|
||||||
|
|
||||||
|
* The history of **all** operations is equivalent to
|
||||||
|
one that took place in some single atomic order but with unknown
|
||||||
|
invocation and completion times - it places no bounds on
|
||||||
|
time or order.
|
||||||
|
"""
|
||||||
|
|
||||||
|
SAME_VIEW_UNDER_PARTITIONS = 'SAME_VIEW_UNDER_PARTITIONS'
|
||||||
|
"""When a client is connected to a server and that server is partitioned
|
||||||
|
from a group of other servers it will (somehow) have the same view of
|
||||||
|
data as a client connected to a server on the other side of the
|
||||||
|
partition (typically this is accomplished by write availability being
|
||||||
|
lost and therefore nothing can change).
|
||||||
|
"""
|
||||||
|
|
||||||
|
SAME_VIEW_ACROSS_CLIENTS = 'SAME_VIEW_ACROSS_CLIENTS'
|
||||||
|
"""A client connected to one server will *always* have the same view
|
||||||
|
every other client will have (no matter what server those other
|
||||||
|
clients are connected to). Typically this is a sacrifice in
|
||||||
|
write availability because before a write can be acknowledged it must
|
||||||
|
be acknowledged by *all* servers in a cluster (so that all clients
|
||||||
|
that are connected to those servers read the exact *same* thing).
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Hooks(list):
|
class Hooks(list):
|
||||||
def run(self, *args, **kwargs):
|
def run(self, *args, **kwargs):
|
||||||
return list(map(lambda cb: cb(*args, **kwargs), self))
|
return list(map(lambda cb: cb(*args, **kwargs), self))
|
||||||
|
@ -72,6 +141,12 @@ class CoordinationDriver(object):
|
||||||
backing store.
|
backing store.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = ()
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._started = False
|
self._started = False
|
||||||
self._hooks_join_group = collections.defaultdict(Hooks)
|
self._hooks_join_group = collections.defaultdict(Hooks)
|
||||||
|
|
|
@ -193,6 +193,15 @@ class FileDriver(coordination._RunWatchersMixin,
|
||||||
account when applying this driver in there app).
|
account when applying this driver in there app).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
HASH_ROUTINE = 'sha1'
|
HASH_ROUTINE = 'sha1'
|
||||||
"""This routine is used to hash a member (or group) id into a filesystem
|
"""This routine is used to hash a member (or group) id into a filesystem
|
||||||
safe name that can be used for member lookup and group joining."""
|
safe name that can be used for member lookup and group joining."""
|
||||||
|
|
|
@ -133,6 +133,15 @@ class IPCDriver(coordination.CoordinationDriver):
|
||||||
.. _IPC: http://en.wikipedia.org/wiki/Inter-process_communication
|
.. _IPC: http://en.wikipedia.org/wiki/Inter-process_communication
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
_SEGMENT_SIZE = 1024
|
_SEGMENT_SIZE = 1024
|
||||||
_GROUP_LIST_KEY = "GROUP_LIST"
|
_GROUP_LIST_KEY = "GROUP_LIST"
|
||||||
_GROUP_PROJECT = "_TOOZ_INTERNAL"
|
_GROUP_PROJECT = "_TOOZ_INTERNAL"
|
||||||
|
|
|
@ -173,6 +173,17 @@ class MemcachedDriver(coordination._RunWatchersMixin,
|
||||||
.. _msgpack: http://msgpack.org/
|
.. _msgpack: http://msgpack.org/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_HOSTS,
|
||||||
|
coordination.Characteristics.CAUSAL,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
#: Key prefix attached to groups (used in name-spacing keys)
|
#: Key prefix attached to groups (used in name-spacing keys)
|
||||||
GROUP_PREFIX = b'_TOOZ_GROUP_'
|
GROUP_PREFIX = b'_TOOZ_GROUP_'
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,16 @@ class MySQLDriver(coordination.CoordinationDriver):
|
||||||
.. _MySQL: http://dev.mysql.com/
|
.. _MySQL: http://dev.mysql.com/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_HOSTS,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, member_id, parsed_url, options):
|
def __init__(self, member_id, parsed_url, options):
|
||||||
"""Initialize the MySQL driver."""
|
"""Initialize the MySQL driver."""
|
||||||
super(MySQLDriver, self).__init__()
|
super(MySQLDriver, self).__init__()
|
||||||
|
|
|
@ -158,6 +158,16 @@ class PostgresDriver(coordination.CoordinationDriver):
|
||||||
.. _PostgreSQL: http://www.postgresql.org/
|
.. _PostgreSQL: http://www.postgresql.org/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_HOSTS,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, member_id, parsed_url, options):
|
def __init__(self, member_id, parsed_url, options):
|
||||||
"""Initialize the PostgreSQL driver."""
|
"""Initialize the PostgreSQL driver."""
|
||||||
super(PostgresDriver, self).__init__()
|
super(PostgresDriver, self).__init__()
|
||||||
|
|
|
@ -160,6 +160,17 @@ class RedisDriver(coordination._RunWatchersMixin,
|
||||||
.. _AOF: http://redis.io/topics/persistence
|
.. _AOF: http://redis.io/topics/persistence
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_HOSTS,
|
||||||
|
coordination.Characteristics.CAUSAL,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
MIN_VERSION = version.LooseVersion("2.6.0")
|
MIN_VERSION = version.LooseVersion("2.6.0")
|
||||||
"""
|
"""
|
||||||
The min redis version that this driver requires to operate with...
|
The min redis version that this driver requires to operate with...
|
||||||
|
|
|
@ -17,6 +17,7 @@ from __future__ import absolute_import
|
||||||
from zake import fake_client
|
from zake import fake_client
|
||||||
from zake import fake_storage
|
from zake import fake_storage
|
||||||
|
|
||||||
|
from tooz import coordination
|
||||||
from tooz.drivers import zookeeper
|
from tooz.drivers import zookeeper
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,6 +32,14 @@ class ZakeDriver(zookeeper.KazooDriver):
|
||||||
.. _zookeeper: http://zookeeper.apache.org/
|
.. _zookeeper: http://zookeeper.apache.org/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
# NOTE(harlowja): this creates a shared backend 'storage' layer that
|
# NOTE(harlowja): this creates a shared backend 'storage' layer that
|
||||||
# would typically exist inside a zookeeper server, but since zake has
|
# would typically exist inside a zookeeper server, but since zake has
|
||||||
# no concept of a 'real' zookeeper server we create a fake one and share
|
# no concept of a 'real' zookeeper server we create a fake one and share
|
||||||
|
|
|
@ -407,6 +407,20 @@ class KazooDriver(BaseZooKeeperDriver):
|
||||||
this option is one of the keys in this dictionary).
|
this option is one of the keys in this dictionary).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
CHARACTERISTICS = (
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_THREADS,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_PROCESSES,
|
||||||
|
coordination.Characteristics.DISTRIBUTED_ACROSS_HOSTS,
|
||||||
|
# Writes *always* go through a single leader process, but it may
|
||||||
|
# take a while for those writes to propagate to followers (and =
|
||||||
|
# during this time clients can read older values)...
|
||||||
|
coordination.Characteristics.SEQUENTIAL,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
Tuple of :py:class:`~tooz.coordination.Characteristics` introspectable
|
||||||
|
enum member(s) that can be used to interogate how this driver works.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, member_id, parsed_url, options):
|
def __init__(self, member_id, parsed_url, options):
|
||||||
super(KazooDriver, self).__init__(member_id, parsed_url, options)
|
super(KazooDriver, self).__init__(member_id, parsed_url, options)
|
||||||
self._coord = self._make_client(parsed_url, self._options)
|
self._coord = self._make_client(parsed_url, self._options)
|
||||||
|
|
Loading…
Reference in New Issue