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:

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]

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.
  1. 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:

$ make server

Creating a Client Bundle

To create a bundle that can run a client and connect to an existing ConCoord instance:

$ 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.

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>
>>>

Table Of Contents

Previous topic

OpenReplica

This Page