For cases when the objects included in the ConCoord distribution do not meet your coordination needs, ConCoord lets you convert your local Python objects into distributable objects very easily.
To walk through the ConCoord approach, you will use a different Counter object that increments and decrements by ten, namely tencounter.py. Once you install ConCoord, you can create coordination objects and save them anywhere in your filesystem. After you create tencounter.py, you can save it under /foo/tencounter.py:
class TenCounter:
def __init__(self, value=0):
self.value = value
def decrement(self):
self.value -= 10
def increment(self):
self.value += 10
def getvalue(self):
return self.value
def __str__(self):
return "The counter value is %d" % self.value
Once you have created the object, update your PYTHONPATH accordingly, so that the objects can be found and imported:
$ export PYTHONPATH=$PYTHONPATH:/foo/
Clients will use a proxy object to do method calls on the object. To create the proxy object automatically, you can use the following command:
$ concoord object -o tencounter.TenCounter
Usage: concoord object [-h] [-o OBJECTNAME] [-t SECURITYTOKEN] [-p PROXYTYPE] [-s] [-v]
-h, --help show this help message and exit
-o OBJECTNAME, --objectname OBJECTNAME client object dotted name module.Class
-t SECURITYTOKEN, --token SECURITYTOKEN security token
-p PROXYTYPE, --proxytype PROXYTYPE 0: basic, 1: blocking, 2: client-side batching, 3: server-side batching
-s, --safe safety checking on/off
-v, --verbose verbose mode on/off
This script will create a proxy file under the directory that the object resides (i.e. /foo/):
/foo/tencounterproxy.py := the proxy that can be used by the client
IMPORTANT NOTE: ConCoord objects treat __init__ functions specially in two ways:
__init__ without any arguments. Therefore, while implementing coordination objects, the __init__ method should be implemented to be able to run without explicit arguments. You can use defaults to implement an __init__ method that accepts arguments.
the Client-Replica connection. This way, multiple clients can connect to a ConCoord instance without reinitializing the object. During proxy generation, the original __init__ function is renamed as __concoordinit__, to reinitialize the object the user can call __concoordinit__ at any point.
After this point on, you can use TenCounter just like we use Counter before.
You can create bundles to use at the server and client sides using the Makefile provided under concoord/
Remember to add the objects you have created in these bundles.
To create a bundle that can run a client and connect to an existing ConCoord instance:
$ make client
We have two kinds of loggers for ConCoord:
Both of these loggers are included under utils.py. To start the NetworkLogger, use the logdaemon.py on the host you want to keep the Logger.
ConCoord provides a distributed and fault-tolerant threading library. The library includes:
The implementations of distributed synchronization objects follow the implementations in the Python threading library. We will walk through an example below using the Semaphore object under concoord/object/semaphore.py
In the blocking object implementation, the method invocations that use an object from the threading library requires an extra argument _concoord_command. This argument is used by the calling Replica node to relate any blocking/unblocking method invocation to a specific client. This way, even if the client disconnects and reconnects, the ConCoord instance will remain in a safe state.
from concoord.threadingobject.dsemaphore import DSemaphore
class Semaphore:
def __init__(self, count=1):
self.semaphore = DSemaphore(count)
def __repr__(self):
return repr(self.semaphore)
def acquire(self, _concoord_command):
try:
return self.semaphore.acquire(_concoord_command)
except Exception as e:
raise e
def release(self, _concoord_command):
try:
return self.semaphore.release(_concoord_command)
except Exception as e:
raise e
def __str__(self):
return str(self.semaphore)
To create the proxy for this blocking object we will use the following command:
$ concoord object -o concoord.object.semaphore.Semaphore -p 1
This command creates the proxy that supports blocking operations. Now you can use blocking objects just like basic ConCoord objects. First, we start the replica nodes the same way we did before as follows:
$ concoord replica -o concoord.object.semaphore.Semaphore -a 127.0.0.1 -p 14000
To test the functionality, you can use multiple clients or print out the Semaphore object as follows:
>>> from semaphoreproxy import Semaphore
>>> s = Semaphore("127.0.0.1:14000")
>>> s.acquire()
True
>>> i = 10
>>> i += 5
>>> s
<DSemaphore count=0>
>>> s.release()
>>> s
<DSemaphore count=1>
>>>