Using Version-Based Consistency

Version-based consistency is used on a per-operation basis. It ensures that a read performed on a replica is at least as current as some previous write performed on the master.

An example of how this might be used is a web application that collects some information from a customer (such as her name). It then customizes all subsequent pages presented to the customer with her name. The storage of the customer's name is a write operation that can only be performed by the master node, while subsequent page creation is performed as a read-only operation that can occur at any node in the store.

Use of this consistency policy might require that version information be transferred between processes in your application.

To create a version-based consistency policy, use the VersionConsistency class. When you do this, you must provide the following information:

For example, the following code performs a store write, collects the version information, then uses it to construct a version-based consistency policy.

from nosqldb import Consistency

from nosqldb import DurabilityException
from nosqldb import Factory
from nosqldb import IllegalArgumentException
from nosqldb import ProxyConfig

from nosqldb import ReadOptions
#### constant needed for ReadOptions
from nosqldb import ONDB_CONSISTENCY
from nosqldb import ONDB_VERSION_CONSISTENCY
from nosqldb import ONDB_TIMEOUT

from nosqldb import RequestTimeoutException
from nosqldb import Row
from nosqldb import StoreConfig
from nosqldb import WriteOptions
##### Constants needed for the write options
from nosqldb import ONDB_RETURN_CHOICE

from nosqldb import VersionConsistency
### Constants needed for the VersionConsistency
from nosqldb import ONDB_TIMEOUT
from nosqldb import ONDB_VERSION

import logging
import os
import sys

# locations where our store and proxy can be found
kvlite = 'localhost:5000'
proxy = 'localhost:7010'

# set logging level to debug and log to stdout
def setup_logging():
    rootLogger = logging.getLogger()
    rootLogger.setLevel(logging.DEBUG)

    logger = logging.StreamHandler(sys.stdout)
    logger.setLevel(logging.DEBUG)
    formatter = logging.Formatter('\t%(levelname)s - %(message)s')
    logger.setFormatter(formatter)
    rootLogger.addHandler(logger)

# configure and open the store
def open_store():
    kvstoreconfig = StoreConfig('kvstore', [kvlite])
    return Factory.open(proxy, kvstoreconfig)

def write_row(store):
    row_d = { 'item' : 'bolts',
               'description' : "Hex head, stainless",
               'count' : 5,
               'percentage' : 0.2173913}
    row = Row(row_d)

    ## Create the write options
    wo = WriteOptions({ONDB_RETURN_CHOICE : 'VERSION'})
    try:
        matchVersion = store.put("myTable", row, wo)
        ## matchVersion is actually a tuple, the second element of 
        ## which identifies the table that the row was written to.
        return matchVersion[0]
    except IllegalArgumentException, iae:
        logging.error("Could not write table.")
        logging.error(iae.message)
    except DurabilityException, de:
        logging.error("Could not write table. Durability failure.")
        logging.error(de.message)
    except RequestTimeoutException, rte:
        logging.error("Could not write table. Exceeded timeout.")
        logging.error(rte.message) 

At some other point in this application's code, or perhaps in another application entirely, we use the matchVersion captured above to create a version-based consistency policy.

def display_row(row):
    try:
            print "Retrieved row:"
            print "\tItem: %s" % row['item']
            print "\tDescription: %s" % row['description']
            print "\tCount: %s" % row['count']
            print "\tPercentage: %s" % row['percentage']
            print "\n"
    except KeyError, ke:
        logging.error("Row display failed. Bad key: %s" % ke.message)

def read_row(store, matchVersion):
    vc = VersionConsistency({ONDB_VERSION : matchVersion,
                            ONDB_TIMEOUT : 1000})

    consistency = Consistency({ONDB_VERSION_CONSISTENCY: vc})


    ro = ReadOptions({ONDB_CONSISTENCY : consistency,
                      ONDB_TIMEOUT : 1000})

    try:
        primary_key_d = {"item" : "bolts"}
        row = store.get("myTable", primary_key_d, ro)
        if not row:
            logging.debug("Row retrieval failed")
        else:
            logging.debug("Row retrieval succeeded.")
            display_row(row)
    except IllegalArgumentException, iae:
        logging.error("Row retrieval failed.")
        logging.error(iae.message)
        return
    except ConsistencyException, ce:
        logging.error("Row retrieval failed due to Consistency.")
        logging.error(ce.message)
    except RequestTimeoutException, rte:
        logging.error("Row retrieval failed, exceeded timeout value.")
        logging.error(rte.message)


if __name__ == '__main__':

    setup_logging()
    store = open_store()
    matchVersion = write_row(store)
    read_row(store, matchVersion)
    store.close()