ConCoordifying Python Objects ----------------------------- 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``: .. sourcecode:: python 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: .. sourcecode:: console $ 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: .. sourcecode:: console $ concoord object -o tencounter.TenCounter ``Usage: concoord object [-h] [-o OBJECTNAME] [-t SECURITYTOKEN] [-p PROXYTYPE] [-s] [-v]`` where, ``-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: 1) When Replicas go live, the object is instantiated calling the ``__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. 2) In the proxy created, the ``__init__`` function is used to initialize 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. Creating Source Bundles ----------------------- 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. Creating a Server Bundle ~~~~~~~~~~~~~~~~~~~~~~~~ To create a bundle that can run replicas: .. sourcecode:: console $ make server Creating a Client Bundle ~~~~~~~~~~~~~~~~~~~~~~~~ To create a bundle that can run a client and connect to an existing ConCoord instance: .. sourcecode:: console $ make client Logging ------- We have two kinds of loggers for ConCoord: * Console Logger * Network Logger 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. Synchronization & Threading --------------------------- ConCoord provides a distributed and fault-tolerant threading library. The library includes: * Lock * RLock * Semaphore * BoundedSemaphore * Barrier * Condition 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. .. sourcecode:: python 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: .. sourcecode:: console $ 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: .. sourcecode:: console $ 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: .. sourcecode:: pycon >>> from semaphoreproxy import Semaphore >>> s = Semaphore("127.0.0.1:14000") >>> s.acquire() True >>> i = 10 >>> i += 5 >>> s >>> s.release() >>> s >>>