"Fossies" - the Fresh Open Source Software Archive

Member "pyzor-1.0.0/pyzor/engines/redis_v0.py" (10 Dec 2014, 4666 Bytes) of package /linux/privat/pyzor-1.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "redis_v0.py" see the Fossies "Dox" file reference documentation.

    1 """Redis database engine.
    2 
    3 XXX Deprecated version.
    4 """
    5 
    6 import logging
    7 import datetime
    8 import functools
    9 
   10 try:
   11     import redis
   12 
   13     _has_redis = True
   14 except ImportError:
   15     redis = None
   16     _has_redis = False
   17 
   18 from pyzor.engines.common import *
   19 
   20 NAMESPACE = "pyzord.digest"
   21 
   22 encode_date = lambda d: "" if d is None else d.strftime("%Y-%m-%d %H:%M:%S")
   23 decode_date = lambda x: None if x == "" else datetime.datetime.strptime(
   24     x, "%Y-%m-%d %H:%M:%S")
   25 
   26 
   27 def safe_call(f):
   28     """Decorator that wraps a method for handling database operations."""
   29 
   30     def wrapped_f(self, *args, **kwargs):
   31         # This only logs the error and raise the usual Error for consistency,
   32         # the redis library takes care of reconnecting and everything else.
   33         try:
   34             return f(self, *args, **kwargs)
   35         except redis.exceptions.RedisError as e:
   36             self.log.error("Redis error while calling %s: %s",
   37                            f.__name__, e)
   38             raise DatabaseError("Database temporarily unavailable.")
   39 
   40     return wrapped_f
   41 
   42 
   43 class RedisDBHandle(BaseEngine):
   44     absolute_source = False
   45     handles_one_step = False
   46 
   47     log = logging.getLogger("pyzord")
   48 
   49     def __init__(self, fn, mode, max_age=None):
   50         self.max_age = max_age
   51         # The 'fn' is host,port,password,db.  We ignore mode.
   52         # We store the authentication details so that we can reconnect if
   53         # necessary.
   54         fn = fn.split(",")
   55         self.host = fn[0] or "localhost"
   56         self.port = fn[1] or "6379"
   57         self.passwd = fn[2] or None
   58         self.db_name = fn[3] or "0"
   59         self.db = self._get_new_connection()
   60 
   61     @staticmethod
   62     def _encode_record(r):
   63         return ("%s,%s,%s,%s,%s,%s" %
   64                 (r.r_count,
   65                  encode_date(r.r_entered),
   66                  encode_date(r.r_updated),
   67                  r.wl_count,
   68                  encode_date(r.wl_entered),
   69                  encode_date(r.wl_updated))).encode()
   70 
   71     @staticmethod
   72     def _decode_record(r):
   73         if r is None:
   74             return Record()
   75         fields = r.decode().split(",")
   76         return Record(r_count=int(fields[0]),
   77                       r_entered=decode_date(fields[1]),
   78                       r_updated=decode_date(fields[2]),
   79                       wl_count=int(fields[3]),
   80                       wl_entered=decode_date(fields[4]),
   81                       wl_updated=decode_date(fields[5]))
   82 
   83     def __iter__(self):
   84         for key in self.db.keys(self._real_key("*")):
   85             yield key.rsplit(".", 1)[-1]
   86 
   87     def _iteritems(self):
   88         for key in self:
   89             try:
   90                 yield key, self[key]
   91             except Exception as ex:
   92                 self.log.warning("Invalid record %s: %s", key, ex)
   93 
   94     def iteritems(self):
   95         return self._iteritems()
   96 
   97     def items(self):
   98         return list(self._iteritems())
   99 
  100     @staticmethod
  101     def _real_key(key):
  102         return "%s.%s" % (NAMESPACE, key)
  103 
  104     @safe_call
  105     def _get_new_connection(self):
  106         if "/" in self.host:
  107             return redis.StrictRedis(unix_socket_path=self.host,
  108                                      db=int(self.db_name), password=self.passwd)
  109         return redis.StrictRedis(host=self.host, port=int(self.port),
  110                                  db=int(self.db_name), password=self.passwd)
  111 
  112     @safe_call
  113     def __getitem__(self, key):
  114         return self._decode_record(self.db.get(self._real_key(key)))
  115 
  116     @safe_call
  117     def __setitem__(self, key, value):
  118         if self.max_age is None:
  119             self.db.set(self._real_key(key), self._encode_record(value))
  120         else:
  121             self.db.setex(self._real_key(key), self.max_age,
  122                           self._encode_record(value))
  123 
  124     @safe_call
  125     def __delitem__(self, key):
  126         self.db.delete(self._real_key(key))
  127 
  128     @classmethod
  129     def get_prefork_connections(cls, fn, mode, max_age=None):
  130         """Yields a number of database connections suitable for a Pyzor
  131         pre-fork server.
  132         """
  133         while True:
  134             yield functools.partial(cls, fn, mode, max_age=max_age)
  135 
  136 
  137 class ThreadedRedisDBHandle(RedisDBHandle):
  138     def __init__(self, fn, mode, max_age=None, bound=None):
  139         RedisDBHandle.__init__(self, fn, mode, max_age=max_age)
  140 
  141 
  142 if not _has_redis:
  143     handle = DBHandle(single_threaded=None,
  144                       multi_threaded=None,
  145                       multi_processing=None,
  146                       prefork=None)
  147 else:
  148     handle = DBHandle(single_threaded=RedisDBHandle,
  149                       multi_threaded=ThreadedRedisDBHandle,
  150                       multi_processing=None,
  151                       prefork=RedisDBHandle)