Source code for pyrakoon.client

# This file is part of Pyrakoon, a distributed key-value store client.
#
# Copyright (C) 2010 Incubaid BVBA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''Arakoon client interface'''

from pyrakoon import errors, protocol
import pyrakoon.utils
from pyrakoon.client.utils import call

[docs]class ClientMixin: #pylint: disable=W0232,R0904,old-style-class '''Mixin providing client actions for standard cluster functionality This can be mixed into any class implementing :class:`AbstractClient`. ''' #pylint: disable=C0111 @call(protocol.Hello)
[docs] def hello(self): #pylint: disable=R0201 assert False
@call(protocol.Exists)
[docs] def exists(self): #pylint: disable=R0201 assert False
@call(protocol.WhoMaster)
[docs] def who_master(self): #pylint: disable=R0201 assert False
@call(protocol.Get)
[docs] def get(self): #pylint: disable=R0201 assert False
@call(protocol.Set)
[docs] def set(self): #pylint: disable=R0201 assert False
@call(protocol.Delete)
[docs] def delete(self): #pylint: disable=R0201 assert False
@call(protocol.PrefixKeys)
[docs] def prefix(self): #pylint: disable=R0201 assert False
@call(protocol.TestAndSet)
[docs] def test_and_set(self): #pylint: disable=R0201 assert False
@call(protocol.Sequence)
[docs] def sequence(self): #pylint: disable=R0201 assert False
@call(protocol.Range)
[docs] def range(self): #pylint: disable=R0201 assert False
@call(protocol.RangeEntries)
[docs] def range_entries(self): #pylint: disable=R0201 assert False
@call(protocol.MultiGet)
[docs] def multi_get(self): #pylint: disable=R0201 assert False
@call(protocol.MultiGetOption)
[docs] def multi_get_option(self): #pylint: disable=R0201 assert False
@call(protocol.ExpectProgressPossible)
[docs] def expect_progress_possible(self): #pylint: disable=R0201 assert False
@call(protocol.GetKeyCount)
[docs] def get_key_count(self): #pylint: disable=R0201 assert False
@call(protocol.UserFunction)
[docs] def user_function(self): #pylint: disable=R0201 assert False
@call(protocol.Confirm)
[docs] def confirm(self): #pylint: disable=R0201 assert False
@call(protocol.Assert)
[docs] def assert_(self): #pylint: disable=R0201 assert False
@call(protocol.RevRangeEntries)
[docs] def rev_range_entries(self): #pylint: disable=R0201 assert False
@call(protocol.Statistics)
[docs] def statistics(self): #pylint: disable=R0201 assert False
@call(protocol.Version)
[docs] def version(self): #pylint: disable=R0201 assert False
@call(protocol.AssertExists)
[docs] def assert_exists(self): #pylint: disable=R0201 assert False
@call(protocol.DeletePrefix)
[docs] def delete_prefix(self): #pylint: disable=R0201 assert False
@call(protocol.Replace)
[docs] def replace(self): #pylint: disable=R0201 assert False
@call(protocol.Nop)
[docs] def nop(self): #pylint: disable=R0201 assert False
@call(protocol.GetCurrentState)
[docs] def get_current_state(self): #pylint: disable=R0201 assert False
__getitem__ = get __setitem__ = set __delitem__ = delete __contains__ = exists
[docs]class NotConnectedError(RuntimeError): '''Error used when a call on a not-connected client is made'''
[docs]class AbstractClient: #pylint: disable=W0232,R0903,R0922,old-style-class '''Abstract base class for implementations of Arakoon clients''' #pylint: disable=pointless-string-statement connected = False '''Flag to denote whether the client is connected If this is :data:`False`, a :class:`NotConnectedError` will be raised when a call is issued. :type: :class:`bool` '''
[docs] def _process(self, message): ''' Submit a message to the server, parse the result and return it The given `message` should be serialized using its :meth:`~pyrakoon.protocol.Message.serialize` method and submitted to the server. Then the :meth:`~pyrakoon.protocol.Message.receive` coroutine of the `message` should be used to retrieve and parse a result from the server. The result value should be returned by this method, or any exceptions should be rethrown if caught. :param message: Message to handle :type message: :class:`pyrakoon.protocol.Message` :return: Server result value :rtype: :obj:`object` :see: :func:`pyrakoon.utils.process_blocking` ''' raise NotImplementedError #pylint: disable=R0904
[docs]class SocketClient(object, AbstractClient): '''Arakoon client using TCP to contact a cluster node :warning: Due to the lack of resource and exception management, this is not intended to be used in real-world code. ''' def __init__(self, address, cluster_id): ''' :param address: Node address (host & port) :type address: `(str, int)` :param cluster_id: Identifier of the cluster :type cluster_id: `str` ''' import threading super(SocketClient, self).__init__() self._lock = threading.Lock() self._socket = None self._address = address self._cluster_id = cluster_id
[docs] def connect(self): '''Create client socket and connect to server''' import socket self._socket = socket.create_connection(self._address) prologue = protocol.build_prologue(self._cluster_id) self._socket.sendall(prologue)
@property def connected(self): '''Check whether a connection is available''' return self._socket is not None
[docs] def _process(self, message): self._lock.acquire() try: for part in message.serialize(): self._socket.sendall(part) return pyrakoon.utils.read_blocking( message.receive(), self._socket.recv) except Exception as exc: if not isinstance(exc, errors.ArakoonError): try: if self._socket: self._socket.close() finally: self._socket = None raise finally: self._lock.release()