Beispiel #1
0
class WordList:
  def __init__(self):
    self.conn = Redis()
    self.CACHE_SIZE = 50
    self.CACHE_KEYS = "words-keys"
    self.CACHE_STORE = "words-store"
    self.WORD_FILE = os.path.join(os.path.expanduser("~"), '.words.txt')

  def _reorganize(self):
    pop_n = self.conn.zcard(self.CACHE_KEYS) - self.CACHE_SIZE
    if pop_n >= 0:
      to_pop = self.conn.zrange(self.CACHE_KEYS, 0, pop_n)
      #print pop_n, to_pop
      self.conn.zremrangebyrank(self.CACHE_KEYS, 0, pop_n)
      for k in to_pop:
        self.conn.hdel(self.CACHE_STORE, k)

  def _add_word(self, key, value):
    result = self.conn.hget(self.CACHE_STORE, key)
    if result:
      self.conn.zincrby(self.CACHE_KEYS, key, 1.0)
    else:
      self._reorganize()
      self.conn.hset(self.CACHE_STORE, key, value)
      self.conn.zadd(self.CACHE_KEYS, 1, key)

  def _get_words(self):
    try:
      words = self.conn.zrevrange(self.CACHE_KEYS, 0, -1, True)
      #hashs = self.conn.hgetall(self.CACHE_STORE)
      #print words
      #print hashs
      return words
    except redis.exceptions.ConnectionError:
      return None

  def dump_console(self):
    if os.path.isfile(self.WORD_FILE):
      with open(self.WORD_FILE, 'r') as f:
        print f.read()

  def write_file(self):
    words = self._get_words()
    if words is None:
      return
    content = '\n'.join(["%d. %s\t %d"%(i, x[0], int(x[1])) for i, x in enumerate(words)])
    with open(self.WORD_FILE, 'w+') as f:
      f.write(content)
      f.write('\n')

  def add_word(self, key):
    try:
      self._add_word(key,key)
      self.write_file()
    except redis.exceptions.ConnectionError:
      return
Beispiel #2
0
class RedisCli(object):
    def __init__(self):
        self.conn = None

    def build_connection(self):
        workerconf = common.conf
        redisconf = dict()
        redisconf['host'] = workerconf["redis_host"]
        redisconf['password'] = workerconf['redis_pass']
        redisconf['port'] = workerconf['redis_port']
        self.conn = StrictRedis(**redisconf)

    def remove_task(self, task_id):
        # move task from running to finished
        self.conn.lrem("running", 1, task_id)
        self.conn.lpush("finished", task_id)

    def run_task(self, task_id):
        # move task from waiting to running
        # task is removed from waiting list by blpop
        self.conn.lpush("running", task_id)

    def recode_bug(self, score, base64_vulnerability):
        # add disclosed vulnerabilities into 'vulnerable' list
        self.conn.zadd("vulnerable", {base64_vulnerability: score})

    def get_request(self):
        _request_id = self.conn.blpop("waiting", 10)
        if _request_id and _request_id[0] == b"waiting":
            request_id = _request_id[1]
        else:
            return None
        result = self.retrieve_request(request_id)
        logger.success("Retrieve one request from 'waiting'.")
        return result

    def retrieve_request(self, request_id):
        _request = self.conn.hget("request", request_id)
        try:
            request = base64.b64decode(_request)
            request_decoded = request.decode("utf8", "ignore")
        except Exception as e:
            logger.error(
                "Error in decoding the request or getting the request : %s" %
                request_id)
            return None
        else:
            return [request_id, request_decoded]

    def delete_request(self, request_id):
        self.conn.hdel("request", request_id)
        return None
class RedisBackend(BaseBackend):
    def __init__(self):
        host = conf.METADATA.get('host', 'localhost')
        port = conf.METADATA.get('port', 6379)
        password = conf.METADATA.get('password', None)
        db = conf.METADATA.get('db', 0)
        prefix = conf.METADATA.get('PREFIX', 'djthumbs')
        self.prefix = prefix + ":"
        self.redis = StrictRedis(host=host,
                                 port=port,
                                 password=password,
                                 db=db)

    def get_source_key(self, name):
        return "%ssources:%s" % (self.prefix, name)

    def get_thumbnail_key(self, name):
        return "%sthumbnails:%s" % (self.prefix, name)

    def add_source(self, name):
        self.redis.hset(self.get_source_key(name), name, name)
        return name

    def get_source(self, name):
        return compat.as_text(self.redis.hget(self.get_source_key(name), name))

    def delete_source(self, name):
        return self.redis.hdel(self.get_source_key(name), name)

    def get_thumbnails(self, name):
        metas = self.redis.hgetall(self.get_thumbnail_key(name))
        return [
            ImageMeta(name, thumbnail_name, size)
            for size, thumbnail_name in metas.items()
        ]

    def get_thumbnail(self, source_name, size):
        name = self.redis.hget(self.get_thumbnail_key(source_name), size)
        if name:
            return ImageMeta(source_name, name, size)
        return None

    def add_thumbnail(self, source_name, size, name):
        self.redis.hset(self.get_thumbnail_key(source_name), size, name)
        return ImageMeta(source_name, name, size)

    def delete_thumbnail(self, source_name, size):
        self.redis.hdel(self.get_thumbnail_key(source_name), size)

    def flush_thumbnails(self, source_name):
        self.redis.delete(self.get_thumbnail_key(source_name))
Beispiel #4
0
def delete(obj, key=None):
    """
    Delete a single key if specified, or all namespace if key is none
    :param obj: settings object
    :param key: key to delete from store location
    :return: None
    """
    client = StrictRedis(**obj.REDIS_FOR_DYNACONF)
    holder = "DYNACONF_%s" % obj.DYNACONF_NAMESPACE
    if key:
        client.hdel(holder.upper(), key.upper())
        obj.unset(key)
    else:
        keys = client.hkeys(holder.upper())
        client.delete(holder.upper())
        obj.unset_all(keys)
Beispiel #5
0
def delete(obj, key=None):
    """
    Delete a single key if specified, or all env if key is none
    :param obj: settings object
    :param key: key to delete from store location
    :return: None
    """
    client = StrictRedis(**obj.REDIS_FOR_DYNACONF)
    holder = obj.get('GLOBAL_ENV_FOR_DYNACONF')
    if key:
        client.hdel(holder.upper(), key.upper())
        obj.unset(key)
    else:
        keys = client.hkeys(holder.upper())
        client.delete(holder.upper())
        obj.unset_all(keys)
Beispiel #6
0
class RedisClient(object):
    def __init__(self, type, website, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD):
        self.db = StrictRedis(host, port, password=password, decode_responses=True)
        self.type = type
        self.website = website

    def name(self):
        return "{type}:{website}".format(type=self.type, website=self.website)

    def set(self, username, value):
        return self.db.hset(self.name(), username, value)

    def get(self, username):
        return self.db.hget(self.name(), username)

    def delete(self, username):
        return self.db.hdel(self.name(), username)

    def count(self):
        return self.db.hlen(self.name())

    def random(self):
        return random.choice(self.db.hvals(self.name()))

    def username(self):
        return self.db.hkeys(self.name())

    def all(self):
        return self.db.hgetall(self.name())

    def all_keys(self):
        return self.db.hkeys(self.name())
Beispiel #7
0
def delete(obj, key=None):
    """
    Delete a single key if specified, or all namespace if key is none
    :param obj: settings object
    :param key: key to delete from store location
    :return: None
    """
    client = StrictRedis(**obj.REDIS_FOR_DYNACONF)
    holder = "DYNACONF_%s" % obj.DYNACONF_NAMESPACE
    if key:
        client.hdel(holder.upper(), key.upper())
        obj.unset(key)
    else:
        keys = client.hkeys(holder.upper())
        client.delete(holder.upper())
        obj.unset_all(keys)
Beispiel #8
0
class RedisBackend(BaseBackend):

    def __init__(self):
        from redis import StrictRedis

        host = conf.METADATA.get('host', 'localhost')
        port = conf.METADATA.get('port', 6379)
        password = conf.METADATA.get('password', None)
        db = conf.METADATA.get('db', 0)
        prefix = conf.METADATA.get('PREFIX', 'djthumbs')
        self.prefix = prefix + ":"
        self.redis = StrictRedis(host=host, port=port, password=password, db=db)

    def get_source_key(self, name):
        return "%ssources:%s" % (self.prefix, name)

    def get_thumbnail_key(self, name):
        return "%sthumbnails:%s" % (self.prefix, name)

    def add_source(self, name):
        self.redis.hset(self.get_source_key(name), name, name)
        return name

    def get_source(self, name):
        return compat.as_text(self.redis.hget(self.get_source_key(name), name))

    def delete_source(self, name):
        return self.redis.hdel(self.get_source_key(name), name)

    def get_thumbnails(self, name):
        metas = self.redis.hgetall(self.get_thumbnail_key(name))
        return [ImageMeta(name, thumbnail_name, size) for size, thumbnail_name in metas.items()]

    def get_thumbnail(self, source_name, size):
        name = compat.as_text(self.redis.hget(self.get_thumbnail_key(source_name), size))
        if name:
            return ImageMeta(source_name, name, size)
        return None

    def add_thumbnail(self, source_name, size, name):
        self.redis.hset(self.get_thumbnail_key(source_name), size, name)
        return ImageMeta(source_name, name, size)

    def delete_thumbnail(self, source_name, size):
        self.redis.hdel(self.get_thumbnail_key(source_name), size)
Beispiel #9
0
class TaskQueue():
    KST_TYPE = 'kst'

    def __init__(self):
        conf = Configuration()
        host = conf.get("redis", "host")
        port = int(conf.get("redis", "port"))
        self.redis_key = "KST:QUEUE:%s" % conf.get("global", "subpub_prefix")
        try:
            self.handler = StrictRedis(host,
                                       port,
                                       retry_on_timeout=True,
                                       socket_timeout=300,
                                       socket_connect_timeout=300)
        except:
            self.handler = StrictRedis(host, port)

    def push(self, job, type):
        topic = "%s:%s" % (self.redis_key, type)

        if isinstance(job, (str, unicode)):
            job = [job]
        logger.info('push task : %s ===> %s' % (topic, dumps(job)))
        return self.handler.rpush(topic, dumps(job))

    def hset(self, field, job, type):
        topic = "%s:%s" % (self.redis_key, type)
        if isinstance(job, (str, unicode)):
            job = [job]
        return self.handler.hset(topic, field, dumps(job))

    def hdel(self, field, type):
        topic = "%s:%s" % (self.redis_key, type)
        return self.handler.hdel(topic, field)

    def pop(self, type):
        topic = "%s:%s" % (self.redis_key, type)
        while True:
            if self.size(topic) == 0:
                time.sleep(1)
                continue
            res = self.handler.lpop(topic)
            logger.info('pop task : %s ===> %s' % (topic, res))
            if res:
                yield loads(res)

    def size(self, topic):
        return self.handler.llen(topic)

    def get(self, key):
        topic = "%s:%s" % (self.redis_key, key)
        return self.handler.get(topic)

    def set(self, key, value, expire=3600):
        topic = "%s:%s" % (self.redis_key, key)
        self.handler.set(topic, value, ex=expire)
class RedisStorage(BaseSharedStorage):
    def __init__(self, db_num):
        self._redis = StrictRedis(db=db_num)

    def save(self, filename, key, data):
        self._purge_duplicates(filename)
        self._redis.hset(filename, key, data)

    def load(self, filename):
        redis_keys = self._redis.hkeys(filename)
        key = redis_keys[0]  # Should never be more than one key
        data = self._redis.hget(filename, key)
        return key, data

    def _purge_duplicates(self, dict_key):
        """Remove identical files from server to be replaced by new files."""
        keys = self._redis.hkeys(dict_key)
        for key in keys:
            self._redis.hdel(dict_key, key)
Beispiel #11
0
def how_redis():
    from redis import StrictRedis
    client = StrictRedis()
    key_list = ['key_' + str(i) for i in range(10)]
    client.delete(*key_list)
    client.zrem('name', *key_list)
    client.hdel('name', 'value', *key_list)
    client.lrem('name', count=0, value=10)
    client.zrange('name', 0, 0, withscores=True)
    client.zremrangebyrank()
    client.zincrby()
    client.zadd()
    client.zinterstore()
    client.mget()
    client.mset()
    pipe = client.pipeline()
    pipe.multi()
    client.zrevrangebyscore()
    client.blpop()
Beispiel #12
0
class RedisClient(object):
    def __init__(self,type_,website):
        self.client = StrictRedis(host=REDIS_HOST,port=REDIS_PORT,password=REDIS_PASS)
        self.website = website
        self.type = type_

    def name(self):
        return "{type}:{website}".format(type=self.type,website=self.website)
        
    

    def set(self,username,value):
        return self.client.hset(self.name(),username,value)
        
    
    def delete(self,username):
        self.client.hdel(self.name(),username)
        
    

    def count(self):
        return self.client.hlen(self.name())
        
    
    def get(self,username):
        return self.client.hget(self.name(),username)
        
    


    def username(self):
        print(self.client.hkeys(self.name()))
        return self.client.hkeys(self.name())
        
    

    def all(self):
        return self.client.hgetall(self.name())
        
    

    def random(self):
        return random.choice(self.client.hvals(self.name()))
Beispiel #13
0
def delete(obj, key=None):
    """
    Delete a single key if specified, or all env if key is none
    :param obj: settings object
    :param key: key to delete from store location
    :return: None
    """
    client = StrictRedis(**obj.REDIS_FOR_DYNACONF)
    holder = obj.get("ENVVAR_PREFIX_FOR_DYNACONF").upper()
    # add env to holder
    holder = f"{holder}_{obj.current_env.upper()}"

    if key:
        client.hdel(holder.upper(), upperfy(key))
        obj.unset(key)
    else:
        keys = client.hkeys(holder.upper())
        client.delete(holder.upper())
        obj.unset_all(keys)
Beispiel #14
0
class RedisDict(MutableMapping):
    """ RedisDict - a dictionary-like interface for ``redis`` key-stores
    """
    def __init__(self,
                 namespace,
                 collection_name='redis_dict_data',
                 connection=None):
        """
        The actual key name on the redis server will be
        ``namespace``:``collection_name``

        In order to deal with how redis stores data/keys,
        everything, i.e. keys and data, must be pickled.

        :param namespace: namespace to use
        :param collection_name: name of the hash map stored in redis
                                (default: redis_dict_data)
        :param connection: ``redis.StrictRedis`` instance.
                           If it's ``None`` (default), a new connection with
                           default options will be created

        """
        if connection is not None:
            self.connection = connection
        else:
            self.connection = Redis()
        self._self_key = ':'.join([namespace, collection_name])

    def __getitem__(self, key):
        result = self.connection.hget(self._self_key, pickle.dumps(key))
        if result is None:
            raise KeyError
        return pickle.loads(bytes(result))

    def __setitem__(self, key, item):
        self.connection.hset(self._self_key, pickle.dumps(key),
                             pickle.dumps(item))

    def __delitem__(self, key):
        if not self.connection.hdel(self._self_key, pickle.dumps(key)):
            raise KeyError

    def __len__(self):
        return self.connection.hlen(self._self_key)

    def __iter__(self):
        for v in self.connection.hkeys(self._self_key):
            yield pickle.loads(bytes(v))

    def clear(self):
        self.connection.delete(self._self_key)

    def __str__(self):
        return str(dict(self.items()))
Beispiel #15
0
	def post_updates(self, updates, log_index):
		'''
			Update the cache with CRUD changes
		'''
		cache = StrictRedis(db=config.tokens_cache_redis_db)
		
		self.log.info('post_updates(): posting updates to local storage')
		for update in updates:			# TODO: could re-add the Redis "Pipelines" feature to combine Redis requests for better performance when available
			(user, token, date, action) = update
			if action == 'add':
				cache.hset('general', token, user)	# future method - user-by-token -- really just existence of a token
				cache.hset('users', user, token)	# future-method - token-by-user: allow lookup of previous token on token changes
				cache.set(token, user)	# Current method
				self.log.info('post_updates(): added token for user: '******'delete':
				cache.hdel('general', token)	# future method - disables the ability to authenticate
				cache.hdel('users', user)	# future method - removes history of token
				cache.delete(token)
				self.log.info('post_updates(): deleted token for user: '******'update':
				prev_token = cache.hget('users', user)
				cache.hdel('general', prev_token)	# future method - disables the ability to authenticate with previous token
				cache.hset('general', token, user)		# future method - set the new token for the user
				cache.hset('users', user, token)		# future method - set the user as possessing the new token
				cache.set(token, user)
				self.log.info('post_updates(): updated token for user: '******'post_updates(): unexpected change type: ' + action)

		if len(updates) > 0:	# don't set if there is nothing to do and also don't set if there are errors
			cache.set('log_index', log_index)
Beispiel #16
0
class RedisDict(MutableMapping):
    """ RedisDict - a dictionary-like interface for ``redis`` key-stores
    """
    def __init__(self, namespace, collection_name='redis_dict_data',
                 connection=None):
        """
        The actual key name on the redis server will be
        ``namespace``:``collection_name``

        In order to deal with how redis stores data/keys,
        everything, i.e. keys and data, must be pickled.

        :param namespace: namespace to use
        :param collection_name: name of the hash map stored in redis
                                (default: redis_dict_data)
        :param connection: ``redis.StrictRedis`` instance.
                           If it's ``None`` (default), a new connection with
                           default options will be created

        """
        if connection is not None:
            self.connection = connection
        else:
            self.connection = Redis()
        self._self_key = ':'.join([namespace, collection_name])

    def __getitem__(self, key):
        result = self.connection.hget(self._self_key, pickle.dumps(key))
        if result is None:
            raise KeyError
        return pickle.loads(bytes(result))

    def __setitem__(self, key, item):
        self.connection.hset(self._self_key, pickle.dumps(key),
                             pickle.dumps(item))

    def __delitem__(self, key):
        if not self.connection.hdel(self._self_key, pickle.dumps(key)):
            raise KeyError

    def __len__(self):
        return self.connection.hlen(self._self_key)

    def __iter__(self):
        for v in self.connection.hkeys(self._self_key):
            yield pickle.loads(bytes(v))

    def clear(self):
        self.connection.delete(self._self_key)

    def __str__(self):
        return str(dict(self.items()))
Beispiel #17
0
 def delete(self, hash_id, identity):
     """
     For Deleting a key inside the hash
     :param hash_id:
     :param identity:
     :return:
     """
     redis = StrictRedis(connection_pool=self.redis_pool)
     hash_key = key_generator(self.hash_key, hash_id)
     key = key_generator(self.key, identity)
     try:
         i = redis.hdel(hash_key, key)
         return i
     except RedisError as re:
         self.log.error("[REDIS] %s", str(re))
         return 0
     finally:
         del redis
Beispiel #18
0
 def delete(self, hash_id, identity):
     """
     For Deleting a key inside the hash
     :param hash_id:
     :param identity:
     :return:
     """
     redis = StrictRedis(connection_pool=self.redis_pool)
     hash_key = key_generator(self.hash_key, hash_id)
     key = key_generator(self.key, identity)
     try:
         i = redis.hdel(hash_key, key)
         return i
     except RedisError as re:
         self.log.error("[REDIS] %s", str(re))
         return 0
     finally:
         del redis
class RedisUse(object):
    def __init__(self):
        self.sr = StrictRedis(host='localhost',
                              port=6379,
                              decode_responses=True)

    def insertTokenOpenid(self, token, openid):
        res = self.sr.set(token, openid)
        res_time = self.sr.expire(token, 7200)

        return res

    def getTokenOpenid(self, token):
        res = self.sr.get(token)

        return res

    def insertOpenidData(self, openid, data):
        res = self.sr.hmset(openid, data)
        res_time = self.sr.expire(openid, 604800)

        return res

    def selectOpenidNature(self, openid):
        res = self.sr.hkeys(openid)

        return res

    def getOpenidNature(self, openid, nature):
        res = self.sr.hget(openid, nature)

        return res

    def getOpenidNatureAll(self, openid):
        res = self.sr.hgetall(openid)

        return res

    def deleteOpenidNature(self, openid, keys):
        res = self.sr.hdel(openid, keys)

        return res
Beispiel #20
0
class RedisBackendTest(TestCase):
    def setUp(self):
        self.backend = RedisBackend()
        self.redis = StrictRedis()

    def test_get_source_key(self):
        self.assertEqual(self.backend.get_source_key("a.jpg"), "djthumbs-test:sources:a.jpg")

    def test_get_thumbnail_key(self):
        self.assertEqual(self.backend.get_thumbnail_key("a.jpg"), "djthumbs-test:thumbnails:a.jpg")

    def test_add_delete_source(self):
        source_name = "test-thumbnail.jpg"
        source_key = self.backend.get_source_key(source_name)

        self.backend.add_source(source_name)
        self.assertTrue(self.redis.hexists(source_key, source_name))
        self.backend.delete_source(source_name)
        self.assertFalse(self.redis.hexists(source_key, source_name))

    def test_get_source(self):
        source_name = "test-thumbnail.jpg"
        source_key = self.backend.get_source_key(source_name)

        self.redis.hset(source_key, source_name, source_name)
        self.assertEqual(self.backend.get_source(source_name), source_name)

        # Delete Source
        self.redis.hdel(source_key, source_name)

    def test_add_delete_thumbnail(self):
        source_name = "test-thumbnail.jpg"
        size = "small"
        thumbnail_key = self.backend.get_thumbnail_key(source_name)

        self.backend.add_source(source_name)
        self.backend.add_thumbnail(source_name, size, "test-thumbnail_small.jpg")
        self.assertTrue(self.redis.hexists(thumbnail_key, size))

        self.backend.delete_thumbnail(source_name, size)
        self.assertFalse(self.redis.hexists(thumbnail_key, size))

        # Delete Source
        self.redis.hdel(self.backend.get_source_key(source_name), source_name)

    def test_get_thumbnail(self):
        source_name = "test-thumbnail.jpg"

        self.backend.add_source(source_name)
        self.backend.add_thumbnail(source_name, "small", "test-thumbnail_small.jpg")
        self.assertEqual(
            self.backend.get_thumbnail(source_name, "small"),
            ImageMeta(source_name, "test-thumbnail_small.jpg", "small"),
        )
        self.backend.add_thumbnail(source_name, "large", "test-thumbnail_large.jpg")

        expected = ["test-thumbnail_large.jpg", "test-thumbnail_small.jpg"]
        result = [image_meta.name for image_meta in self.backend.get_thumbnails(source_name)]
        self.assertEqual(result.sort(), expected.sort())

        # Delete Source & Thumbnails
        thumbnail_key = self.backend.get_thumbnail_key(source_name)
        self.redis.hdel(self.backend.get_source_key(source_name), source_name)
        self.redis.hdel(thumbnail_key, "small")
        self.redis.hdel(thumbnail_key, "large")
Beispiel #21
0
class RedisConn(object):
    """docstring for RedisConn"""

    def __init__(self, startup_nodes=None, host="localhost",
                 port=6379, db=0, password=None, encoding='utf-8',
                 socket_keepalive=False, connection_pool=None,
                 max_connections=None, project="", decode_responses=True, **kwargs):
        if project:
            project = f'{project}:'
        self.cluster_flag = False
        self.project = project
        if startup_nodes:
            from rediscluster import StrictRedisCluster
            if isinstance(startup_nodes, (str, bytes)):
                startup_nodes = _normalize_startup_nodes(startup_nodes)
            self._redis = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=decode_responses,
                                             skip_full_coverage_check=True, **kwargs)
            self.cluster_flag = True
        else:
            self._redis = StrictRedis(host=host, port=port, db=db, password=password,
                                      socket_keepalive=socket_keepalive, connection_pool=connection_pool,
                                      max_connections=max_connections, **kwargs)

    def add_head(self, key):
        return f'{self.project}{key}'

    def format_key():
        def make_wrapper(func):
            def wrapper(self, key, *args, **kwargs):
                new_key = self.add_head(key)
                return func(self, new_key, *args, **kwargs)
            return wrapper
        return make_wrapper

    def format_key_keys():
        def make_wrapper(func):
            def wrapper(self, key, keys, *args, **kwargs):
                new_key = self.add_head(key)
                new_keys = list(map(self.add_head, keys))
                return func(self, new_key, new_keys, *args, **kwargs)
            return wrapper
        return make_wrapper

    def format_args():
        def make_wrapper(func):
            def wrapper(self, *args, **kwargs):
                new_args = list(map(self.add_head, list(args)))
                return func(self, *new_args, **kwargs)
            return wrapper
        return make_wrapper

    def format_two_key():
        def make_wrapper(func):
            def wrapper(self, src, dst, *args, **kwargs):
                new_src = self.add_head(src)
                new_dst = self.add_head(dst)
                return func(self, new_src, new_dst, *args, **kwargs)
            return wrapper
        return make_wrapper

    def format_keys():
        def make_wrapper(func):
            def wrapper(self, keys, *args):
                new_keys = list(map(self.add_head, keys))
                return func(self, new_keys, *args)
            return wrapper
        return make_wrapper

    def format_dicts():
        def make_wrapper(func):
            def wrapper(self, mapping, *args):
                new_mapping = {}
                for key in mapping.keys():
                    new_key = self.add_head(key)
                    new_mapping[new_key] = mapping[key]
                return func(self, new_mapping, *args)
            return wrapper
        return make_wrapper

    @format_args()
    def unlink(self, *keys):
        """
        time complexity O(1)
        redis异步删除keys
        """
        return self._redis.unlink(*keys)

    def pipeline(self, transaction=True, shard_hint=None):
        """
        返回一个pipe对象
        """
        return self._redis.pipeline(transaction, shard_hint)

    """===============================string-start=========================="""
    # }
    @format_key()
    def set(self, key, value, ex=None, px=None, nx=False, xx=False):
        """
        time complexity O(1)
        Set the value at key ``key`` to ``value``
        Arguments:
            key (str):     key key
            value (str):    key value
            ex(int):    过期时间(秒)
            px(int):    过期时间(豪秒)
            nx(bool):   如果设置为True,则只有key不存在时,当前set操作才执行(新建)
            xx(bool):   如果设置为True,则只有key存在时,当前set操作才执行 (修改)
        Returns:
            result(bool): 是否成功成功是True失败可能是None
        """
        return self._redis.set(key, value, ex, px, nx, xx)

    @format_key()
    def get(self, key):
        """
        time complexity O(1)
        Return the value at ``key``, or None if the key doesn't exist
        Arguments:
            key (str):     key
        Returns:
            value (str):返回value
        """
        return self._redis.get(key)

    @format_key()
    def getset(self, key, value):
        """
        time complexity O(1)
        设置新值并获取原来的值
        """
        return self._redis.getset(key, value)

    @format_key()
    def strlen(self, key):
        """
        time complexity O(1)
        获得key对应的value长度
        """
        return self._redis.strlen(key)

    @format_key()
    def getrange(self, key, start, end):
        """
        time complexity O(1)
        获得key对应的value的start到end长度字符返回
        """
        return self._redis.getrange(key, start, end)

    @format_key()
    def setrange(self, key, offset, value):
        """
        time complexity O(1)
        设置key对应的value从offset地方用新value替换
        """
        return self._redis.setrange(key, offset, value)

    @format_key()
    def setbit(self, key, offset, value):
        """
        time complexity O(1)
        value值只能是1或0
        设置key对应的value二进制在offset位用value替换
        """
        return self._redis.setbit(key, offset, value)

    @format_key()
    def getbit(self, key, offset):
        """
        time complexity O(1)
        获取key对应的value二进制在offset位的值
        """
        return self._redis.getbit(key, offset)

    @format_key()
    def expire(self, key, time):
        """
        time complexity O(1)
        设置key的过期时间s
        """
        return self._redis.expire(key, time)

    @format_key()
    def pexpire(self, key, time):
        """
        time complexity O(1)
        设置key的过期时间ms
        """
        return self._redis.pexpire(key, time)

    @format_key()
    def pexpireat(self, key, when):
        """
        time complexity O(1)
        设置key的过期时间(在什么时候过期)
        when是uninx的时间戳ms
        """
        return self._redis.pexpireat(key, when)

    @format_key()
    def pttl(self, key):
        """
        time complexity O(1)
        获得key过期时间(ms),没有设置过期时间返回-1
        """
        return self._redis.pttl(key)

    @format_key()
    def ttl(self, key):
        """
        time complexity O(1)
        获得name过期时间(s),没有设置过期时间返回-1
        """
        return self._redis.ttl(key)

    @format_dicts()
    def mset(self, mapping):
        """
        time complexity O(n)
        Arguments:
            mapping (dict):   {name: value,name1: value1}
        Returns:
            return ok
        """
        return self._redis.mset(mapping)

    @format_dicts()
    def msetnx(self, mapping):
        """
        time complexity O(n)
        Arguments:
            mapping (dict):   {name: value,name1: value1}
        Returns:
            return (bool): 与mset区别是指定的key中有任意一个已存在,则不进行任何操作,返回错误
        """
        return self._redis.msetnx(mapping)

    @format_keys()
    def mget(self, keys, *args):
        """
        time complexity O(n)
        Arguments:
            keys (list): [name, name1]
        Returns:
            return (list): 返回对应keys的value, name在数据库不存在返回None
        Mind!:
            一次性取多个key确实比get提高了性能,但是mget的时间复杂度O(n),
            实际使用过程中测试当key的数量到大于100之后性能会急剧下降,
            建议mget每次key数量不要超过100。在使用前根据实列的redis吞吐量可能会不一样。
        """
        return self._redis.mget(keys, *args)

    @format_key()
    def incr(self, key, amount=1):
        """
        time complexity O(1)
        将key对应的value值自增amount,并返回自增后的值。只对可以转换为整型的String数据起作用。
        用于统计sql型数据库大表里面的数据量
        """
        return self._redis.incr(key, amount)

    @format_key()
    def incrbyfloat(self, key, amount=1.0):
        """
        time complexity O(1)
        amount 可以为负数代表减法
        将key对应的value值自增amount,并返回自增后的值。只对可以转换为float的String数据起作用。
        用于统计sql型数据库大表里面的数据量
        """
        return self._redis.incrbyfloat(key, amount)

    @format_key()
    def decr(self, key, amount=1):
        """
        time complexity O(1)
        将key对应的value值自减amount,并返回自减后的值。只对可以转换为整型的String数据起作用。
        用于统计sql型数据库大表里面的数据量
        """
        return self._redis.decr(key, amount)

    def keys(self, pattern='*'):
        """
        time complexity O(n)
        获取匹配pattern的所有key.实际项目中慎用
        """
        return self._redis.keys(pattern)

    @format_key()
    def move(self, key, db):
        """
        time complexity O(1)
        移动key到其他db
        """
        return self._redis.move(key, db)

    def randomkey(self):
        """
        time complexity O(1)
        随机返回一个key
        """
        return self._redis.randomkey()

    @format_args()
    def rename(self, src, dst):
        """
        time complexity O(1)
        重命名key src to dst
        """
        return self._redis.rename(src, dst)

    @format_args()
    def exists(self, *keys):
        """
        time complexity O(1)
        查看keys是否存在返回存在的key数量
        """
        return self._redis.exists(*keys)

    @format_args()
    def delete(self, *keys):
        """
        time complexity O(1)
        删除keys
        """
        return self._redis.delete(*keys)

    @format_key()
    def type(self, key):
        """
        time complexity O(1)
        查看key对应value类型
        """
        return self._redis.type(key)
# {
    """===============================string-end============================"""

    """===============================list-start============================"""
# }
    @format_keys()
    def blpop(self, keys, timeout=0):
        """
        如果keys里面有list为空要求整个服务器被阻塞以保证块执行时的原子性,
        该行为阻止了其他客户端执行 LPUSH 或 RPUSH 命令
        阻塞的一个命令,用来做轮询和会话配合使用
        Arguments:
            keys(list): [keys, keys]
            timeout(int): S
        """
        return self._redis.blpop(keys, timeout)

    @format_keys()
    def brpop(self, keys, timeout=0):
        """
        同上,取数据的方向不同
        """
        return self._redis.brpop(keys, timeout)

    @format_two_key()
    def brpoplpush(self, src, dst, timeout=0):
        """
        从src表尾取一个数据插入dst表头。同上src为空阻塞
        """
        return self._redis.brpoplpush(src, dst, timeout)

    @format_key()
    def lpush(self, key, *values):
        """
        time complexity O(n)
        Set the value at key ``key`` to ``value``
        Arguments:
            key (str):     key key
            value (list):    key value
        Returns:
            result(int): 插入成功之后list长度
        """
        return self._redis.lpush(key, *values)

    @format_key()
    def lpushx(self, key, *values):
        """
        time complexity O(n)
        only key not exists
        Arguments:
            key (str):     key
            value (list):    key value
        Returns:
            result(int): 插入成功之后list长度
        """
        return self._redis.lpushx(key, *values)

    @format_key()
    def lpop(self, key):
        """
        time complexity O(1)
        移除并返回列表 key 的头元素。
        """
        return self._redis.lpop(key)

    @format_key()
    def rpush(self, key, *values):
        """
        time complexity O(n)
        Set the value at key ``key`` to ``value``
        Arguments:
            key (str):     key key
            value (list):    key value
        Returns:
            result(int): 插入成功之后list长度
        """
        return self._redis.rpush(key, *values)

    @format_key()
    def rpushx(self, key, *values):
        """
        time complexity O(n)
        only key not exists
        Arguments:
            key (str):     key
            value (list):    key value
        Returns:
            result(int): 插入成功之后list长度
        """
        return self._redis.rpushx(key, *values)

    @format_key()
    def rpop(self, key):
        """
        time complexity O(1)
        移除并返回列表 key尾元素。
        """
        return self._redis.rpop(key)

    @format_key()
    def lrange(self, key, start, end):
        """
        time complexity O(n)
        获取list数据包含start,end.在不清楚list的情况下尽量不要使用lrange(key, 0, -1)操作
        应尽可能控制一次获取的元素数量
        """
        return self._redis.lrange(key, start, end)

    @format_args()
    def rpoplpush(self, src, dst):
        """
        从src表尾取一个数据插入dst表头
        """
        return self._redis.rpoplpush(src, dst)

    @format_key()
    def llen(self, key):
        """
        time complexity O(1)
        获取list长度,如果key不存在返回0,如果key不是list类型返回错误
        """
        return self._redis.llen(key)

    @format_key()
    def lindex(self, key, index):
        """
        time complexity O(n) n为经过的元素数量
        返回key对应list的index位置的value
        """
        return self._redis.lindex(key, index)

    @format_key()
    def linsert(self, key, where, refvalue, value):
        """
        time complexity O(n) n为经过的元素数量
        key或者refvalue不存在就不进行操作
        Arguments:
            where(str): BEFORE|AFTER  后|前
            refvalue(str): list里面的值
        """
        return self._redis.linsert(key, where, refvalue, value)

    @format_key()
    def lrem(self, key, count, value):
        """
        time complexity O(n)
        删除count数量的value
        Arguments:
            count(int): count>0 表头开始搜索
                        count<0 表尾开始搜索
                        count=0 删除所有与value相等的数值
        Returns:
            result(int): 删除的value的数量
        """
        if self.cluster_flag:
            return self._redis.lrem(key, value, count)
        return self._redis.lrem(key, count, value)

    @format_key()
    def lset(self, key, index, value):
        """
        time complexity O(n)
        设置list的index位置的值,没有key和超出返回错误
        """
        return self._redis.lset(key, index, value)

    @format_key()
    def ltrim(self, key, start, end):
        """
        time complexity O(n) n为被删除的元素数量
        裁剪让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
        """
        return self._redis.ltrim(key, start, end)

    @format_key()
    def sort(self, key, start=None, num=None, by=None, get=None,
             desc=False, alpha=False, store=None, groups=False):
        """
        time complexity O(n)
        O(N+M*log(M)), N 为要排序的列表或集合内的元素数量, M 为要返回的元素数量。
        删除count数量的value
        Arguments:
            by(str): 让排序按照外部条件排序,
                    可以先将权重插入redis然后再作为条件进行排序如(user_level_*)
            get(str): redis有一组user_name_*然后*是按照list里面的值,
                    按照排序取一个个key的value
            store(str): 保留sort之后的结果,可以设置expire过期时间作为结果缓存
            alpha: 按照字符排序
            desc: 逆序
        Returns:
            result(list): 排序之后的list
        """
        return self._redis.sort(key, start, num, by, get, desc, alpha, store, groups)

    def scan(self, cursor=0, match=None, count=None):
        """
        time complexity O(1) 单次
        增量迭代返回redis数据库里面的key,因为是增量迭代过程中返回可能会出现重复
        Arguments:
            cursor(int): 游标
            match(str): 匹配
            count(int): 每次返回的key数量
        Returns:
            result(set): 第一个是下次scan的游标,后面是返回的keys(list)当返回的游标为0代表遍历完整个redis
        """
        return self._redis.scan(cursor, match, count)
# {
    """===============================list-end===================================="""

    """===============================hash-start==================================="""
# }
    @format_key()
    def hdel(self, key, *names):
        """
        time complexity O(n) n为names长度
        Return the value at ``key``, or None if the key doesn't exist
        Arguments:
            key (str):     key
            names(list): hash里面的域
        Returns:
            result (int): 成功删除的个数
        """
        return self._redis.hdel(key, *names)

    @format_key()
    def hexists(self, key, name):
        """
        time complexity O(1)
        判断key中是否有name域
        """
        return self._redis.hexists(key, name)

    @format_key()
    def hget(self, key, name):
        """
        time complexity O(1)
        """
        return self._redis.hget(key, name)

    @format_key()
    def hgetall(self, key):
        """
        time complexity O(n)
        """
        return self._redis.hgetall(key)

    @format_key()
    def hincrby(self, key, name, amount=1):
        """
        time complexity O(1)
        amount可以为负数,且value值为整数才能使用否则返回错误
        """
        return self._redis.hincrby(key, name, amount)

    @format_key()
    def hincrbyfloat(self, key, name, amount=1.0):
        """
        time complexity O(1)
        """
        return self._redis.hincrbyfloat(key, name, amount)

    @format_key()
    def hkeys(self, key):
        """
        time complexity O(n)
        """
        return self._redis.hkeys(key)

    @format_key()
    def hlen(self, key):
        """
        time complexity O(1)
        """
        return self._redis.hlen(key)

    @format_key()
    def hset(self, key, name, value):
        """
        time complexity O(1)
        """
        return self._redis.hset(key, name, value)

    @format_key()
    def hsetnx(self, key, name, value):
        """
        time complexity O(1)
        """
        return self._redis.hsetnx(key, name, value)

    @format_key()
    def hmset(self, key, mapping):
        """
        time complexity O(n)
        """
        return self._redis.hmset(key, mapping)

    @format_key()
    def hmget(self, key, names, *args):
        """
        time complexity O(n)
        """
        return self._redis.hmget(key, names, *args)

    @format_key()
    def hvals(self, key):
        """
        time complexity O(n)
        返回hash表所有的value
        """
        return self._redis.hvals(key)

    @format_key()
    def hstrlen(self, key, name):
        """
        time complexity O(1)
        """
        return self._redis.hstrlen(key, name)
# {
    """=================================hash-end==================================="""

    """=================================set-start================================="""
# }
    @format_key()
    def sadd(self, key, *values):
        """
        time complexity O(n) n为values长度
        """
        return self._redis.sadd(key, *values)

    @format_key()
    def scard(self, key):
        """
        time complexity O(n) set长度
        返回set大小
        """
        return self._redis.scard(key)

    @format_args()
    def sdiff(self, key, *args):
        """
        time complexity O(n) N 是所有给定集合的成员数量之和
        返回差集成员的列表。
        """
        return self._redis.sdiff(key, *args)

    @format_args()
    def sdiffstore(self, dest, keys, *args):
        """
        time complexity O(n) N 是所有给定集合的成员数量之和
        返回差集成员的数量。并将结果保存到dest这个set里面
        """
        return self._redis.sdiffstore(dest, keys, *args)

    @format_args()
    def sinter(self, key, *args):
        """
        time complexity O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
        返回交集数据的list
        """
        return self._redis.sinter(key, *args)

    @format_args()
    def sinterstore(self, dest, keys, *args):
        """
        time complexity O(n) N 是所有给定集合的成员数量之和
        返回交集成员的数量。并将结果保存到dest这个set里面
        """
        return self._redis.sinterstore(dest, keys, *args)

    @format_key()
    def sismember(self, key, name):
        """
        time complexity O(1)
        判断name是否在key中
        """
        return self._redis.sismember(key, name)

    @format_key()
    def smembers(self, key):
        """
        time complexity O(n)
        返回set里面所有成员
        """
        return self._redis.smembers(key)

    @format_two_key()
    def smove(self, src, dst, value):
        """
        time complexity O(1)
        将value从src移动到dst原子性操作
        """
        return self._redis.smove(src, dst, value)

    @format_key()
    def spop(self, key, count=None):
        """
        time complexity O(n) n
        默认随机删除一条, 删除count条
        """
        return self._redis.spop(key, count)

    @format_key()
    def srandmember(self, key, number=None):
        """
        time complexity O(n) n
        默认随机返回一条, 返回number条
        """
        return self._redis.srandmember(key, number)

    @format_key()
    def srem(self, key, *values):
        """
        time complexity O(n) n为values长度
        移除key里面values
        """
        return self._redis.srem(key, *values)

    @format_args()
    def sunion(self, keys, *args):
        """
        time complexity O(N), N 是所有给定集合的成员数量之和
        返回并集
        """
        return self._redis.sunion(keys, *args)

    @format_args()
    def sunionstore(self, dest, keys, *args):
        """
        time complexity O(N), N 是所有给定集合的成员数量之和。
        求并集并保存
        """
        return self._redis.sunionstore(dest, keys, *args)

    @format_key()
    def sscan(self, key, cursor=0, match=None, count=None):
        """
        time complexity O(1)
        同scan只是这个是set使用
        """
        return self._redis.sscan(key, cursor, match, count)
# {
    """==================================set-end=================================="""

    """===============================SortedSet-start============================="""
# }
    @format_key()
    def zadd(self, key, mapping, nx=False, xx=False, ch=False, incr=False):
        """
        time complexity O(M*log(N)), N 是有序集的基数, M 为成功添加的新成员的数量。
        Arguments:
            mapping(dict): (value:score)
            XX(bool): 仅仅更新存在的成员,不添加新成员。
            NX(bool): 不更新存在的成员。只添加新成员。
            CH(bool): 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。
                      更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。
                      注:在通常情况下,ZADD返回值只计算新添加成员的数量。
            INCR(bool): 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
        Returns:
            result(int): 成功插入数量
        """
        if self.cluster_flag:
            return self._redis.zadd(key, **mapping)
        return self._redis.zadd(key, mapping, nx, xx, ch, incr)

    @format_key()
    def zcard(self, key):
        """
        time complexity O(1)
        返回zset()基数
        """
        return self._redis.zcard(key)

    @format_key()
    def zcount(self, key, minz, maxz):
        """
        time complexity O(log(N)), N 为有序集的基数。
        返回score在min和max之间的value的个数
        """
        return self._redis.zcount(key, minz, maxz)

    @format_key()
    def zincrby(self, key, amount, value):
        """
        time complexity O(log(N)), N 为有序集的基数。
        amount 可以为负数
        """
        if self.cluster_flag:
            return self._redis.zincrby(key, value, amount)
        return self._redis.zincrby(key, amount, value)

    @format_key_keys()
    def zinterstore(self, dest, keys, aggregate=None):
        """
        time complexity O(N*K)+O(M*log(M)), N 为给定 key 中基数最小的有序集, K 为给定有序集的数量, M 为结果集的基数。
        求交集并按照aggregate做处理之后保存到dest。默认是求和
        Arguments:
            aggregate(str):sum 和, min 最小值, max 最大值
        返回新zset里面的value个数
        """
        return self._redis.zinterstore(dest, keys, aggregate)

    @format_key()
    def zrange(self, key, start, end, desc=False, withscores=False,
               score_cast_func=float):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
        Arguments:
            start,有序集合索引起始位置(非分数)
            end,有序集合索引结束位置(非分数)
            desc,排序规则,默认按照分数从小到大排序
            withscores,是否获取元素的分数,默认只获取元素的值
            score_cast_func,对分数进行数据转换的函数
        """
        return self._redis.zrange(key, start, end, desc, withscores, score_cast_func)

    @format_key()
    def zrevrange(self, key, start, end, withscores=False, score_cast_func=float):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
        Arguments:
            start,有序集合索引起始位置(非分数)
            end,有序集合索引结束位置(非分数)
            withscores,是否获取元素的分数,默认只获取元素的值
            score_cast_func,对分数进行数据转换的函数
        """
        return self._redis.zrevrange(key, start, end, withscores, score_cast_func)

    @format_key()
    def zrangebyscore(self, key, minz, maxz, start=None, num=None, withscores=False, score_cast_func=float):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
        有序集成员按 score 值递增(从小到大)次序排列。
        """
        return self._redis.zrangebyscore(key, minz, maxz, start, num, withscores, score_cast_func)

    @format_key()
    def zrevrangebyscore(self, key, minz, maxz, start=None, num=None, withscores=False, score_cast_func=float):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
        有序集成员按 score 值递减(从大到小)次序排列。
        """
        return self._redis.zrevrangebyscore(key, minz, maxz, start, num, withscores, score_cast_func)

    @format_key()
    def zrangebylex(self, key, minz, maxz, start=None, num=None):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
        有序集成员按 value 字典序递增(从小到大)次序排列。
        """
        return self._redis.zrangebylex(key, minz, maxz, start, num)

    @format_key()
    def zrevrangebylex(self, key, minz, maxz, start=None, num=None):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
        有序集成员按 value 字典序递减(从大到小)次序排列。
        """
        return self._redis.zrevrangebylex(key, minz, maxz, start, num)

    @format_key()
    def zrank(self, key, value):
        """
        time complexity O(log(N))
        查找zset里面这个value的rank排名从0开始
        """
        return self._redis.zrank(key, value)

    @format_key()
    def zrevrank(self, key, value):
        """
        time complexity O(log(N))
        查找zset里面这个value的rank排名从0开始
        """
        return self._redis.zrevrank(key, value)

    @format_key()
    def zrem(self, key, *values):
        """
        time complexity O(M*log(N)), N 为有序集的基数, M 为被成功移除的成员的数量
        删除zset里面单个或者多个成员
        """
        return self._redis.zrem(key, *values)

    @format_key()
    def zremrangebylex(self, key, minz, maxz):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为被移除成员的数量。
        按照字典增序范围删除
        """
        return self._redis.zremrangebylex(key, minz, maxz)

    @format_key()
    def zremrangebyrank(self, key, minz, maxz):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为被移除成员的数量。
        按照rank范围删除
        """
        return self._redis.zremrangebyrank(key, minz, maxz)

    @format_key()
    def zremrangebyscore(self, key, minz, maxz):
        """
        time complexity O(log(N)+M), N 为有序集的基数,而 M 为被移除成员的数量。
        按照score范围删除
        """
        return self._redis.zremrangebyscore(key, minz, maxz)

    @format_key()
    def zscore(self, key, value):
        """
        time complexity O(log(N))
        查找zset里面这个value的score排名从0开始
        """
        return self._redis.zscore(key, value)

    @format_key_keys()
    def zunionstore(self, dest, keys, aggregate=None):
        """
        time complexity O(N)+O(M log(M)), N 为给定有序集基数的总和, M 为结果集的基数。
        求并集保存
        """
        return self._redis.zunionstore(dest, keys, aggregate)

    @format_key()
    def zscan(self, key, cursor=0, match=None, count=None, score_cast_func=float):
        """
        time complexity O(1)
        同SCAN
        """
        return self._redis.zscan(key, cursor, match, count, score_cast_func)

    def zlexcount(self, key, minz, maxz):
        """
        time complexity O(log(N)),其中 N 为有序集合包含的元素数量。
        min -负无限  [闭空间不包括自己 (开空间包括自己
        max +正无限 [a, (c
        """
        return self._redis.zlexcount(key, minz, maxz)
# {
    """===============================SortedSet-end================================="""
    """===============================HyperLogLog-start==============================="""
# }
    @format_key()
    def pfadd(self, key, *values):
        """
        time complexity O(n)
        """
        return self._redis.pfadd(key, *values)

    @format_args()
    def pfcount(self, *sources):
        """
        time complexity O(1)
        计算key的基数
        """
        return self._redis.pfcount(*sources)

    @format_args()
    def pfmerge(self, dest, *sources):
        """
        time complexity O(n) 其中 N 为被合并的 HyperLogLog 数量,不过这个命令的常数复杂度比较高
        合并HyperLogLog
        """
        return self._redis.pfmerge(dest, *sources)
# {
    """===============================HyperLogLog-end================================="""

    """==================================GEO-start===================================="""
# }
    @format_key()
    def geoadd(self, key, *values):
        """
        time complexity O(log(N)) 每添加一个元素的复杂度为 O(log(N)) , 其中 N 为键里面包含的位置元素数量。
        """
        return self._redis.geoadd(key, *values)

    @format_key()
    def geopos(self, key, *values):
        """
        time complexity O(log(N))
        从键里面返回所有给定位置元素的位置(经度和纬度)。
        """
        return self._redis.geopos(key, *values)

    @format_key()
    def geohash(self, key, *values):
        """
        time complexity O(log(N))
        命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应
        """
        return self._redis.geohash(key, *values)

    @format_key()
    def geodist(self, key, place1, place2, unit=None):
        """
        time complexity O(log(N))
        返回两个给定位置之间的距离。
        Argument:
            unit : m: 米,km: 千米,mi: 英里,ft: 英尺
        """
        return self._redis.geodist(key, place1, place2, unit)

    @format_key()
    def georadius(self, key, longitude, latitude, radius, unit=None,
                  withdist=False, withcoord=False, withhash=False, count=None,
                  sort=None, store=None, store_dist=None):
        """
        time complexity O(N+log(M)), 其中 N 为指定半径范围内的位置元素数量, 而 M 则是被返回位置元素的数量。
        以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
        Argument:
            longitude: 经度
            latitude: 纬度
            radius: 距离
            unit: 距离单位
            withdist: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
            withcoord: 将位置元素的经度和维度也一并返回
            withhash: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。
                      这个选项主要用于底层应用或者调试, 实际中的作用并不大。
            sort: 根据中心的位置排序 ASC,DESC
            count: 取前多少个
            store: 保存
            store_dist: 存储地名和距离
        Return:
            list(list)
            [['Foshan', 109.4922], ['Guangzhou', 105.8065]]
        """
        return self._redis.georadius(key, longitude, latitude, radius, unit, withdist, withcoord,
                                     withhash, count, sort, store, store_dist)

    @format_key()
    def georadiusbymember(self, key, member, radius, unit=None,
                          withdist=False, withcoord=False, withhash=False, count=None,
                          sort=None, store=None, store_dist=None):
        """
        time complexity O(N+log(M)), 其中 N 为指定半径范围内的位置元素数量, 而 M 则是被返回位置元素的数量。
        以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
        Argument:
            member: 位置元素
            radius: 距离
            unit: 距离单位
            withdist: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
            withcoord: 将位置元素的经度和维度也一并返回
            withhash: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
            sort: 根据中心的位置排序 ASC,DESC
            count: 取前多少个
            store: 保存
            store_dist: 存储地名和距离
        Return:
            list(list)
            [['Foshan', 109.4922], ['Guangzhou', 105.8065]]
        """
        return self._redis.georadiusbymember(key, member, radius, unit, withdist, withcoord,
                                             withhash, count, sort, store, store_dist)

# {
    """==================================GEO-end======================================"""
Beispiel #22
0
class CustomClient(WebWxClient):
    def __init__(self):
        super().__init__()
        self.r = StrictRedis(REDIS_HOST,
                             REDIS_PORT,
                             REDIS_DB,
                             decode_responses=True)
        keys = self.r.keys('chatbot:*')
        if keys:
            self.r.delete(*keys)
        self.conn = pika.BlockingConnection(
            pika.ConnectionParameters(RABBIT_HOST, RABBIT_PORT))
        self.receive_channel = self.conn.channel()
        self.receive_channel.queue_declare(queue=RECEIVE_QUEUE)

        # rabbitmq heartbeat keeping thread
        scheduler = BackgroundScheduler()
        scheduler.add_job(lambda conn: conn.process_data_events(),
                          'interval',
                          seconds=10,
                          args=[self.conn])
        scheduler.start()

    def after_login(self):
        # persist cookie
        self.r.hmset("chatbot:client:cookie", self.session.cookies.get_dict())
        # chatid is webwx's username
        self.r.set('chatbot:client:self_chatid', self.user.username)
        username_dict = {}
        nickname_dict = {}
        remark_name_dict = {}
        for contact in self.contacts.values():
            username = contact.username
            nickname_dict[username] = contact.nickname
            # set a default remark name when contact has no remark name
            if not contact.remark_name:
                # do not record record without remark name
                remark_name = self._gen_remark_name(contact.nickname)
                # do not to modify redis data immediately
                # modify it when receiving webwx message and the function handle_modify_contacts called
                self.webwxoplog(contact.username, remark_name)
            else:
                username_dict[username] = contact.remark_name
                remark_name_dict[contact.remark_name] = username
        if username_dict:
            self.r.hmset('chatbot:client:username_remark_name_mapping',
                         username_dict)
        if nickname_dict:
            self.r.hmset('chatbot:client:username_nickname_mapping',
                         nickname_dict)
        if remark_name_dict:
            self.r.hmset('chatbot:client:remark_name_username_mapping',
                         remark_name_dict)

        self._persist_contact_data()

    def handle_text(self, msg):
        self._publish(msg)

    def handle_image(self, msg):
        self._publish(msg)

    def handle_emotion(self, msg):
        self._publish(msg)

    def handle_location(self, msg):
        self._publish(msg)

    def handle_update_contacts(self, username_list):
        for username in username_list:
            if username in self.chatrooms:
                self._update_chatroom_member_data(self.chatrooms[username])
            # update username remark_name mapping
            self.r.hset('chatbot:client:remark_name_username_mapping',
                        self.contacts[username].remark_name, username)
            old_remark_name = self.r.hget(
                'chatbot:client:username_remark_name_mapping', username)
            # remove the old remark name
            self.r.hdel('chatbot:client:remark_name_username_mapping',
                        old_remark_name)
            self.r.hset('chatbot:client:username_remark_name_mapping',
                        username, self.contacts[username].remark_name)
            self.r.hset('chatbot:client:username_nickname_mapping', username,
                        self.contacts[username].nickname)

    def _persist_contact_data(self):
        for special_user in self.special_users.values():
            self.r.hmset(
                'chatbot:client:special_user:'******'chatbot:client:media_platform:' + chatroom.username,
                         chatroom.json)
        for media_platform in self.media_platforms.values():
            self.r.hmset(
                'chatbot:client:media_platform:' + media_platform.username,
                media_platform.json)
        for friend in self.friends.values():
            self.r.hmset('chatbot:client:friend:' + friend.username,
                         friend.json)

    def _update_chatroom_member_data(self, chatroom):
        chatroom_username_nickname_dict = {}
        chatroom_username_display_name_dict = {}
        member_list = chatroom.member_list
        for member in member_list.values():
            # set user nickname who is not your friend but in the chatroom
            chatroom_username_nickname_dict[member.username] = member.nickname
            chatroom_username_display_name_dict[
                member.username] = member.display_name
        self.r.hmset('chatbot:client:username_nickname_mapping',
                     chatroom_username_nickname_dict)
        self.r.hmset(
            'chatbot:client:chatroom:' + chatroom.username +
            ':username_display_name_mapping',
            chatroom_username_display_name_dict)

    def _publish(self, msg):
        self.logger.info(msg.json)
        self.receive_channel.basic_publish(exchange='',
                                           routing_key=RECEIVE_QUEUE,
                                           body=json.dumps(msg.json))

    @staticmethod
    def _gen_remark_name(nickname):
        return nickname + str(random.randint(100, 999))
Beispiel #23
0
def delete_sid(sid):
    cli = StrictRedis(connection_pool=pool)
    cli.hdel("user_sid", sid)
Beispiel #24
0
class RedisDatabase:
    """
	docstring for RedisDatabase
	"""
    def __init__(self, password=""):
        self.start_redis()

    def is_redis_running(self):
        try:
            if sys.platform == 'win32':
                process = len(
                    os.popen('tasklist | findstr ' +
                             "redis-server.exe").readlines())
                if process >= 1:
                    return True
                else:
                    return False
            elif sys.platform == 'darwin':
                # macOS
                return True
            else:
                # other platform
                return True
        except Exception as e:
            raise Exception(
                'Unable to check redis running staate,error message: ' +
                str(e))

    def start_redis(self, password=''):
        try:
            if not self.is_redis_running():
                if sys.platform == 'win32':
                    os.system("e:/redis/redis-server --service-start")
                elif sys.platform == 'darwin':
                    # macOS
                    pass
                else:
                    pass
        except Exception as e:
            raise Exception('Unble to start redis, error message: ' + str(e))
        try:
            self.datadb = StrictRedis(host='localhost', port=6379, db=0)
            self.cachedb = StrictRedis(host='localhost',
                                       port=6379,
                                       db=1,
                                       decode_responses=True)
            self.hashdb = StrictRedis(host='localhost', port=6379, db=2)
        except Exception as e:
            raise Exception('Redis connection failed,error message:' + str(e))

    def stop_redis(self):
        try:
            if self.is_redis_running():
                # self.flushall()
                if sys.platform == 'win32':
                    os.system("e:/redis/redis-server --service-stop")
                elif sys.platform == 'darwin':
                    pass
                else:
                    pass
        except Exception as e:
            raise Exception('Unble to stop redis,error message:' + str(e))

    def set_value(self, obj, data_source):
        """
		Using a dictionary, a Mongdb object, a Net class, a Attr class, a DynamicNet class or a DynamicAttr class
			to set a new entry in Redis.
		"""
        if type(obj) is dict:
            key = self.generate_static_key(data_source, obj['scan'],
                                           obj['atlas'], obj['feature'])
            self.datadb.set(key, obj['value'], ex=1800)
            return self.trans_netattr(obj['scan'],
                                      obj['atlas'], obj['feature'],
                                      pickle.loads(obj['value']))
        elif type(obj) is pymongo.cursor.Cursor:
            value = []
            scan = obj[0]['scan']
            atlas = obj[0]['atlas']
            feature = obj[0]['feature']
            window_length = obj[0]['window_length']
            step_size = obj[0]['step_size']
            key_all = self.generate_dynamic_key(data_source, scan, atlas,
                                                feature, window_length,
                                                step_size)
            pipe = self.datadb.pipeline()
            length = obj.count()
            try:
                pipe.multi()
                pipe.set(key_all + ':0', length, ex=1600)
                for i in range(length):  # 使用查询关键字保证升序
                    pipe.set(key_all + ':' + str(i + 1), (obj[i]['value']),
                             ex=1800)
                    value.append(pickle.loads(obj[i]['value']))
                pipe.execute()
            except Exception as e:
                raise Exception(
                    'An error occur when tring to set value in redis, error message: '
                    + str(e))
            return self.trans_dynamic_netattr(scan, atlas, feature,
                                              window_length, step_size,
                                              np.array(value))
        elif type(obj) is netattr.Net or type(obj) is netattr.Attr:
            key = self.generate_static_key(data_source, obj.scan,
                                           obj.atlasobj.name, obj.feature_name)
            self.atadb.set(key, pickle.dumps(obj.data))
        elif type(obj) is netattr.DynamicNet or type(
                obj) is netattr.DynamicAttr:
            key_all = self.generate_dynamic_key(data_source, obj.scan,
                                                obj.atlasobj.name,
                                                obj.feature_name,
                                                obj.window_length,
                                                obj.step_size)
            length = obj.data.shape[2]
            pipe = self.datadb.pipeline()
            if type(obj) is netattr.DynamicNet:
                flag = True
            else:
                flag = False
            try:
                pipe.multi()
                pipe.set(key_all + ':0', length, ex=1600)
                for i in range(length):  # 使用查询关键字保证升序
                    if flag:
                        pipe.set(key_all + ':' + str(i + 1),
                                 pickle.dumps(obj.data[:, :, i]),
                                 ex=1800)
                    else:
                        pipe.set(key_all + ':' + str(i + 1),
                                 obj.data[:, i],
                                 ex=1800)
                pipe.execute()
            except Exception as e:
                raise Exception(
                    'An error occur when tring to set value in redis, error message: '
                    + str(e))

    def generate_static_key(self, data_source, subject_scan, atlas_name,
                            feature_name):
        key = data_source + ':' + subject_scan + ':' + atlas_name + ':' + feature_name + ':0'
        return key

    def generate_dynamic_key(self, data_source, subject_scan, atlas_name,
                             feature_name, window_length, step_size):
        key = data_source + ':' + subject_scan + ':' + atlas_name + ':' + feature_name + ':1:' + str(
            window_length) + ':' + str(step_size)
        return key

    def get_static_value(self, data_source, subject_scan, atlas_name,
                         feature_name):
        """
		Using data source, scan name, altasobj name, feature name to query static networks and attributes from Redis.
		If the query succeeds, return a Net or Attr class, if not, return none.
		"""
        key = self.generate_static_key(data_source, subject_scan, atlas_name,
                                       feature_name)
        res = self.datadb.get(key)
        self.datadb.expire(key, 1800)
        if res is not None:
            return self.trans_netattr(subject_scan, atlas_name, feature_name,
                                      pickle.loads(res))
        else:
            return None

    def trans_netattr(self, subject_scan, atlas_name, feature_name, value):
        if value.ndim == 1:  # 这里要改一下
            arr = netattr.Attr(value, atlas.get(atlas_name), subject_scan,
                               feature_name)
            return arr
        else:
            net = netattr.Net(value, atlas.get(atlas_name), subject_scan,
                              feature_name)
            return net

    def get_dynamic_value(self, data_source, subject_scan, atlas_name,
                          feature_name, window_length, step_size):
        """
		Using data source, scan name, altasobj name, feature name, window length, step size to query dynamic
			networks and attributes from Redis.
		If the query succeeds, return a DynamicNet or DynamicAttr class, if not, return none.
		"""
        key_all = self.generate_dynamic_key(data_source, subject_scan,
                                            atlas_name, feature_name,
                                            window_length, step_size)
        if self.datadb.exists(key_all + ':0'):
            pipe = self.datadb.pipeline()
            try:
                pipe.multi()
                length = int(self.datadb.get(key_all + ':0').decode())
                for i in range(1, length + 1, 1):
                    pipe.get(key_all + ':' + str(i))
                res = pipe.execute()
            except Exception as e:
                raise Exception(
                    'An error occur when tring to get value in redis, error message: '
                    + str(e))
            try:
                pipe.multi()
                value = []
                for i in range(length):
                    value.append(pickle.loads(res[i]))
                    pipe.expire(key_all + ':' + str(i + 1), 1800)
                pipe.expire(key_all + ':0', 1600)
                pipe.execute()
            except Exception as e:
                raise Exception(
                    'An error occur when tring to update expiration time in redis, error message: '
                    + str(e))
            return self.trans_dynamic_netattr(subject_scan, atlas_name,
                                              feature_name, window_length,
                                              step_size, np.array(value))
        else:
            return None

    def trans_dynamic_netattr(self, subject_scan, atlas_name, feature_name,
                              window_length, step_size, value):
        if value.ndim == 2:  # 这里要改一下
            arr = netattr.DynamicAttr(value.swapaxes(0, 1),
                                      atlas.get(atlas_name), window_length,
                                      step_size, subject_scan, feature_name)
            return arr
        else:
            net = netattr.DynamicNet(
                value.swapaxes(0, 2).swapaxes(0, 1), atlas.get(atlas_name),
                window_length, step_size, subject_scan, feature_name)
            return net

    def exists_key(self,
                   data_source,
                   subject_scan,
                   atlas_name,
                   feature_name,
                   isdynamic=False,
                   window_length=0,
                   step_size=0):
        """
		Using data source, scan name, atlas name, feature name to check the existence of an static entry in Redis.
		You can add isdynamic(True), window length, step size to check the existence of an dynamic entry in Redis.
		"""
        if isdynamic is False:
            return self.datadb.exists(
                self.generate_static_key(data_source, subject_scan, atlas_name,
                                         feature_name))
        else:
            return self.datadb.exists(
                self.generate_dynamic_key(data_source, subject_scan,
                                          atlas_name, feature_name,
                                          window_length, step_size) + ':0')

    """
	Redis supports storing and querying list as cache.
	Note: the items in list must be int or float.
	"""

    def set_list_all_cache(self, key, value):
        """
		Store a list to Redis as cache with cache_key.
		Note: please check the existence of the cache_key, or it will cover the origin entry.
		"""
        self.cachedb.delete(key)
        for i in value:
            self.cachedb.rpush(key, i)
        #self.cachedb.save()
        return self.cachedb.llen(key)

    def set_list_cache(self, key, value):
        """
		Append value to a list as the last one in Redis with cache_key.
		If the given key is empty in Redis, a new list will be created.
		"""
        self.cachedb.rpush(key, value)
        #self.cachedb.save()
        return self.cachedb.llen(key)

    def get_list_cache(self, key, start=0, end=-1):
        """
		Return a list with given cache_key in Redis.
		"""
        res = self.cachedb.lrange(key, start, end)
        lst = []
        for x in res:
            if x.isdigit():
                lst.append(int(x))
            else:
                lst.append(float(x))
        return lst

    def exists_key_cache(self, key):
        """
		Check the existence of a list in Redis by cache_key.
		"""
        return self.cachedb.exists(key)

    def delete_key_cache(self, key):
        """
		Delete an entry in Redis by cache_key.
		If the given key is empty in Redis, do nothing.
		"""
        value = self.cachedb.delete(key)
        #self.cachedb.save()
        return value

    def clear_cache(self):
        """
		Delete all the entries in Redis.
		"""
        self.cachedb.flushdb()

    """
	Redis supports storing and querying hash.
	Note: the keys in hash must be string.
	"""

    def set_hash_all(self, name, hash):
        """
		Store a hash to Redis with hash_name and a hash.
		Note: please check the existence of the hash_name, or it will cover the origin hash.
		"""
        self.hashdb.delete(name)
        for i in hash:
            hash[i] = pickle.dumps(hash[i])
        self.hashdb.hmset(name, hash)

    def set_hash(self, name, item1, item2=''):
        """
		Append an entry/entries to a hash in Redis with hash_name.
		If the given name is empty in Redis, a new hash will be created.
		The input format should be as follows:
			1.A hash
			2.A key and a value
		"""
        if type(item1) is dict:
            for i in item1:
                item1[i] = pickle.dumps(item1[i])
            self.hashdb.hmset(name, item1)
        else:
            self.hashdb.hset(name, item1, pickle.dumps(item2))

    def get_hash(self, name, keys=[]):
        """
		Support three query functions:
			1.Return a hash with a given hash_name in Redis.
			2.Return a value_list with a given hash_name and a key_list in Redis,
				the value_list is the same sequence as key_list.
			3.Return a value with a given hash_name and a key in Redis.
		"""
        if not keys:
            res = self.hashdb.hgetall(name)
            hash = {}
            for i in res:
                hash[i.decode()] = pickle.loads(res[i])
            return hash
        else:
            if type(keys) is list:
                res = self.hashdb.hmget(name, keys)
                for i in range(len(res)):
                    res[i] = pickle.loads(res[i])
                return res
            else:
                return pickle.loads(self.hashdb.hget(name, keys))

    def exists_hash(self, name):
        """
		Check the existence of a hash in Redis by hash_name.
		"""
        return self.hashdb.exists(name)

    def exists_hash_key(self, name, key):
        """
		Check the existence of a key in a given hash by key_name and hash_name.
		"""
        return self.hashdb.hexists(name, key)

    def delete_hash(self, name):
        """
		Delete a hash in Redis by hash_name.
		"""
        self.hashdb.delete(name)

    def delete_hash_key(self, name, key):
        """
		Delete a key in a given hash by key_name and hash_name.
		"""
        self.hashdb.hdel(name, key)

    def clear_hash(self):
        """
		Delete all the hashes in Redis by hash_name.
		"""
        self.hashdb.flushdb()

    def flushall(self):
        self.datadb.flushall()
Beispiel #25
0
    'Bob': 88,
    'Lee': 78,
    'Ming': 99
}))  #python3之后传字典
print(redis.zrem('grade', 'Bob'))
print(redis.zincrby('grade', 2.2, 'Mike'))  #...新版本倒一下参数就好了
print(redis.zrank('grade', 'Lee'))  #获取正数排名
print(redis.zrevrank('grade', 'Lee'))  #获取倒数排名
print(redis.zrevrange('grade', 1, 2))
print(redis.zrevrangebyscore('grade', 99, 80))
print(redis.zcount('grade', 70, 100))  #分数在70~100的元素个数
print(redis.zcard('grade'))  #统计集合grade元素个数
print(redis.zremrangebyrank('grade', 1, 3))
redis.zadd('grade', {'Mike': 100, 'Bob': 88, 'Lee': 78, 'Ming': 99})
print(redis.zrevrangebyscore('grade', 78, 100))

# 7.散列
print()
print(redis.hset('price', 'cake', 5))
print(redis.hsetnx('price', 'book', 50))
print(redis.hget('price', 'cake'))
print(redis.hmget('price', ['cake', 'book']))
print(redis.hmset('price', {'keyboard': 22, 'mouse': 10}))
print(redis.hincrby('price', 'cake', 1))
print(redis.exists('price', 'book'))
print(redis.hdel('price', 'keyboard'))
print(redis.hlen('price'))
print(redis.hkeys('price'))  #获取所有映射的键名
print(redis.hvals('price'))  #获取所有映射的键值
print(redis.hgetall('price'))  #获取所有的映射
Beispiel #26
0

# 向散列表中批量新增/更新映射数据
redis.hmset('price', {'apple':2, 'orange':7})


# 给映射 value 做加法
redis.hincrby('price', 'apple', 2)


# 判断映射 key 是否存在
print(redis.hexists('price','banana'))


# 删除一个映射键值对
redis.hdel('price', 'banana')


# 获取散列表长度
print(redis.hlen('price'))


# 获取散列表中所有映射 key
print(redis.hkeys('price'))


# 获取散列表中所有映射 value
print(redis.hvals('price'))


# 获取散列表中所有映射键值对
Beispiel #27
0
from redis import StrictRedis

if __name__ == '__main__':
    strict_redis = StrictRedis(decode_responses=True)
    strict_redis.hdel('cart1', 'goods1', 'goods2', 'goods3')
    # 1.id为1的用户添加了商品到购物车
    # strict_redis.hset('cart1', 'goods1', 2)
    # strict_redis.hset('cart1', 'goods2', 3)
    strict_redis.hmset('cart1', {'goods1': 2, 'goods2': 3})

    # 2.取出用户购买的id为1的商品的数量,商品购买数量加1后,再保存回去
    goods1 = strict_redis.hget('cart1', 'goods1')
    goods2 = strict_redis.hget('cart1', 'goods2')
    strict_redis.hset('cart1', 'goods1', int(goods1) + 1)
    # strict_redis.hset('cart1', 'goods2', int(goods2) + 1)

    goods1 = strict_redis.hget('cart1', 'goods1')
    goods2 = strict_redis.hget('cart1', 'goods2')

    # 3.统计用户添加添加到购物车商品的总数量(3+4=7件)
    print('goods1:%s个' % goods1)
    print('goods2:%s个' % goods2)

    vals = strict_redis.hvals('cart1')
    print(vals)
    ret = sum([int(val) for val in vals])
    print('商品共计:%d个' % ret)

    # 4.用户从购物车中删除了id为1的商品
    strict_redis.hdel('cart1', 'goods1')
    print(strict_redis.hgetall('cart1'))
zrangebyscore(name, min, max, start=None, num=None, withscores=False)	返回key为name的zset中score在给定区间的元素	                                                                  redis.zrangebyscore('grade', 80, 95)	            [b'Amy', b'James']
zcount(name, min, max)	                                                返回key为name的zset中score在给定区间的数量	                                                                  redis.zcount('grade', 80, 95)	                          2
zcard(name)	                                                            返回key为name的zset的元素个数	                                                                             redis.zcard('grade')	                                 3
zremrangebyrank(name, min, max)	                                        删除key为name的zset中排名在给定区间的元素	                                                                   redis.zremrangebyrank('grade', 0, 0)	             1,即删除的元素个数
zremrangebyscore(name, min, max)                                        删除key为name的zset中score在给定区间的元素	                                                                  redis.zremrangebyscore('grade', 80, 90)	        1,即删除的元素个数

\Hash操作
            方法	                    作用	                                        示例	                                  示例结果
hset(name, key, value)	        向key为name的hash中添加映射	                     hset('price', 'cake', 5)	                   1,即添加的映射个数
hsetnx(name, key, value)	    向key为name的hash中添加映射,如果映射键名不存在	    hsetnx('price', 'book', 6)	                  1,即添加的映射个数
hget(name, key)	                返回key为name的hash中field对应的value	         redis.hget('price', 'cake')	                     5
hmget(name, keys, *args)	    返回key为name的hash中各个键对应的value	          redis.hmget('price', ['apple', 'orange'])	     [b'3', b'7']
hmset(name, mapping)	        向key为name的hash中批量添加映射	                  redis.hmset('price', {'banana': 2, 'pear': 6})	True
hincrby(name, key, amount=1)	将key为name的hash中映射的value增加amount	     redis.hincrby('price', 'apple', 3)	            6,修改后的值
hexists(name, key)	            key为namehash中是否存在键名为key的映射	          redis.hexists('price', 'banana')	                 True
hdel(name, *keys)	            key为namehash中删除键名为key的映射	             redis.hdel('price', 'banana')	                     True
hlen(name)	                    从key为name的hash中获取映射个数	                 redis.hlen('price')	                               6
hkeys(name)	                    从key为name的hash中获取所有映射键名	              redis.hkeys('price')	                    [b'cake', b'book', b'banana', b'pear']
hvals(name)	                    从key为name的hash中获取所有映射键值	              redis.hvals('price')	                    [b'5', b'6', b'2', b'6']
hgetall(name)	                从key为name的hash中获取所有映射键值对	           redis.hgetall('price')	       {b'cake': b'5', b'book': b'6', b'orange': b'7', b'pear': b'6'}

\RedisDump
# redis-load
#将数据导入到数据库中
redis-load -h   # 获取帮助信息
< redis_data.json redis-load -u redis://@localhost:6379  # 将json数据导入数据库中

#redis-dump
#将数据库信息导出
redis-dump -h  # 获取帮助信息
redis-dump -u redis://@localhost:6379 -d 1 > ./redis.data.jl  # 导出到json文件
Beispiel #29
0
class RedisLRU(object):
    def __init__(self, redis=None, **kwargs):
        if redis is not None:
            self._redis = redis
        else:
            self._redis = Redis(**kwargs)
        self.namespaces = {
            "default": 10000
        }

    def setup_namespace(self, namespace, size):
        """Set the LRU Size for a namespace.
        """
        self.namespaces[namespace] = int(size)

    def _serialize(self, s):
        # return json.dumps(s)
        return s

    def _unserialize(self, s):
        # s = s.decode("utf-8")
        # return json.loads(s)
        return s

    def _size(self, namespace):
        return self.namespaces[namespace]

    def _hit_store(self, namespace):
        if namespace not in self.namespaces:
            raise KeyError("invalid namespace")
        return "cache_keys_{}".format(namespace)

    def _value_store(self, namespace):
        if namespace not in self.namespaces:
            raise KeyError("invalid namespace")
        return "cache_values_{}".format(namespace)

    def _expire_old(self, namespace):
        hits = self._hit_store(namespace)
        size = self._size(namespace)
        count = self._redis.zcard(hits)
        if count >= size:
            values = self._value_store(namespace)
            items = self._redis.zrange(hits, 0, count-size)
            logger.error(items)
            self._redis.zremrangebyrank(hits, 0, count-size)
            self._redis.hdel(values, *items)

    def clear(self, namespace="default"):
        """Clear the Cache.
        """
        hits = self._hit_store(namespace)
        values = self._value_store(namespace)
        self._redis.delete(hits, values)

    def clearAll(self):
        """Clear all known namespaces.
        """
        for k in self.namespaces.iterkeys():
            self.clear(k)

    def store(self, key, value, namespace="default"):
        """Store a key value pair in cache.
        This will not update an existing item.
        """
        values = self._value_store(namespace)
        if not self._redis.hexists(values, key):
            hits = self._hit_store(namespace)
            self._expire_old(namespace)
            self._redis.hset(values, key, self._serialize(value))
            self._redis.zadd(hits, time.time(), key)
        else:
            hits = self._hit_store(namespace)
            self._redis.hset(values, key, self._serialize(value))
            self._redis.zadd(hits, time.time(), key)

    def get(self, key, namespace="default"):
        """Get a value from the cache.
        returns none if the key is not found.
        """
        values = self._value_store(namespace)
        value = self._redis.hget(values, key)
        if value:
            hits = self._hit_store(namespace)
            self._redis.zadd(hits, time.time(), key)
            return self._unserialize(value)
        return None

    def expire(self, key, namespace="default"):
        """Expire (invalidate) a key from the cache.
        """
        values = self._value_store(namespace)
        if self._redis.hexists(values, key):
            hits = self._hit_store(namespace)
            self._redis.hdel(values, key)
            self._redis.zrem(hits, key)
Beispiel #30
0
class RedisBackend:

    colls_index_fmt = 'plumbca:' + dfconf['mark_version'] + ':collections:index'
    metadata_fmt = 'plumbca:' + dfconf['mark_version'] + ':metadata:timeline:{name}'
    inc_coll_cache_fmt = 'plumbca:' + dfconf['mark_version'] + ':cache:{name}'
    sorted_count_coll_cache_fmt = 'plumbca:' + dfconf['mark_version'] + \
                                  ':sorted:count:cache:{name}:{tagging}:{ts}'
    unique_count_coll_cache_fmt = 'plumbca:' + dfconf['mark_version'] + \
                                  ':unique:count:cache:{name}:{tagging}:{ts}'

    def __init__(self):
        self.rdb = StrictRedis(host=rdconf['host'], port=rdconf['port'],
                               db=rdconf['db'])
        self.version = dfconf['mark_version']

    def set_collection_index(self, name, instance):
        """ Set the collection info of instance to the backend.
        """
        key = self.colls_index_fmt
        v = instance.__class__.__name__
        self.rdb.hset(key, name, packb(v))

    def get_collection_index(self, name):
        """ Get the collection info from backend by name.
        """
        key = self.colls_index_fmt
        rv = self.rdb.hget(key, name)
        return [name, unpackb(rv)] if rv else None

    def get_collection_indexes(self):
        """ Get all of the collections info from backend.
        """
        key = self.colls_index_fmt
        rv = self.rdb.hgetall(key)
        if rv:
            return {name.decode("utf-8"): unpackb(info)
                        for name, info in rv.items()}

    def delete_collection_keys(self, coll, klass=''):
        """ Danger! This method will erasing all values store in the key that
        should be only use it when you really known what are you doing.

        It is good for the testing to clean up the environment.
        """
        md_key = self.metadata_fmt.format(name=coll.name)
        self.rdb.delete(md_key)

        if klass == 'IncreaseCollection':
            cache_key = self.inc_coll_cache_fmt.format(name=coll.name)
            self.rdb.delete(cache_key)

    def get_collection_length(self, coll, klass=''):
        if not klass:
            klass = coll.__class__.__name__

        rv = []
        md_key = self.metadata_fmt.format(name=coll.name)
        md_len = self.rdb.zcard(md_key)
        rv.append(md_len)
        # print('** TL -', self.rdb.zrange(md_key, 0, -1, withscores=True))

        if klass == 'IncreaseCollection':
            cache_key = self.inc_coll_cache_fmt.format(name=coll.name)
            cache_len = self.rdb.hlen(cache_key)
            # notice that the cache_len is the length of all the items in cache_key
            rv.append(cache_len)

        return rv

    def set_collection_metadata(self, coll, tagging, expts, ts, *args):
        """ Insert data to the metadata structure if timestamp data do not
        exists. Note that the metadata structure include two types, timeline
        and expire.

        :param coll: collection class
        :param tagging: specific tagging string
        :param ts: the timestamp of the data
        :param expts: the expired timestamp of the data
        """
        md_key = self.metadata_fmt.format(name=coll.name)
        # Ensure the item of the specific `ts` whether it's exists or not,
        element = self.rdb.zrangebyscore(md_key, ts, ts)

        if element:
            info = unpackb(element[0])
            if tagging in info:
                # the tagging info already exists then do nothings
                return
            info[tagging] = [expts] + list(args)
            # remove the md_key and update new value atomically
            p = self.rdb.pipeline()
            p.zremrangebyscore(md_key, ts, ts)
            p.zadd(md_key, ts, packb(info))
            p.execute()

        else:
            info = {tagging: [expts] + list(args)}
            self.rdb.zadd(md_key, ts, packb(info))
        # print('-'*10)
        # print(tagging)
        # print(self.rdb.zrange(md_key, 0, -1, withscores=True))
        # print('+'*10)

    def del_collection_metadata_by_items(self, coll, tagging, items):
        """Delete the items of the metadata with the privided timestamp list.

        :param items: the items query from metadata, structure should be equal
                      to the format of the metadata query that specified tagging.
        """
        md_key = self.metadata_fmt.format(name=coll.name)
        self._del_collection_metadata(md_key, tagging, items)

    def del_collection_metadata_by_range(self, coll, tagging, start, end):
        """Delete the items of the metadata with the privided start time and
        end time arguments.
        """
        md_key = self.metadata_fmt.format(name=coll.name)
        elements = self.rdb.zrangebyscore(md_key, start, end, withscores=True)
        if not elements:
            return

        self._del_collection_metadata(md_key, tagging, elements)

    def _del_collection_metadata(self, key, tagging, elements):
        del_info_todos = []
        del_key_todos = []

        # searching what elements need te be handle
        for info, ts in elements:
            if isinstance(info, bytes):
                info = unpackb(info)
            if tagging not in info:
                continue
            info.pop(tagging)
            # when info has not element then should remove the ts key,
            # otherwise should update new value to it.
            if info:
                del_info_todos.append((info, ts))
            else:
                del_key_todos.append(ts)

        # doing the operations that update keys one by one atomically
        for info, ts in del_info_todos:
            p = self.rdb.pipeline()
            p.zremrangebyscore(key, ts, ts)
            p.zadd(key, ts, packb(info))
            p.execute()

        # doing the operations that remove all keys atomically
        p = self.rdb.pipeline()
        for ts in del_key_todos:
            p.zremrangebyscore(key, ts, ts)
        p.execute()

    def query_collection_metadata(self, coll, tagging, start, end, ret_whold=False):
        return self._query_collection_metadata(coll, start, end,
                                               tagging, ret_whold)

    def query_collection_metadata_tagging(self, coll, start, end):
        return self._query_collection_metadata(coll, start, end, '__taggings__')

    def query_collection_metadata_all(self, coll, start, end):
        return self._query_collection_metadata(coll, start, end, '__all__')

    def _query_collection_metadata(self, coll, start, end, tagging='', ret_whold=False):
        """ Do the real operations for query metadata from the redis.

        :param coll: the collection class use to fetch name
        :param start: the start time of the query
        :param end: the end time of the query
        :param tagging: the tagging for query
        :param ret_whold: whether return all the info when specified a tagging

        :ret: return None if no data exists.
              If tagging is specified '__taggings__', return value only contain the taggings:
                  # ts: all_tagging
                  {
                      ts1: [tagging1, tagging2, ..., targetN],
                      ts2: [tagging1, tagging2, ..., targetN],
                      ...
                      tsN: [tagging1, tagging2, ..., targetN],
                  }
              If tagging is specified '__all__', return value include all the info:
                  # ts: all_tagging_info
                  {
                      ts1: {tagging1: info1, tagging2: info2, ...},
                      ts2: {tagging1: info1, tagging2: info2, ...},
                      ...
                      tsN: {tagging1: info1, tagging2: info2, ...},
                  }
              If tagging is specified other, return value is the info that match the tagging:
                  # value, score if ret_whold == False
                  [(info1, ts1), (info2, ts2), ... (infoN, tsN)]
                  # else:
                  [
                      ({tagging1: info1, tagging2: info2, ...}, ts1),
                      ({tagging1: info1, tagging2: info2, ...}, ts2),
                      ...
                      ({tagging1: info1, tagging2: info2, ...}, tsN),
                  ]
        """
        md_key = self.metadata_fmt.format(name=coll.name)
        elements = self.rdb.zrangebyscore(md_key, start, end, withscores=True)
        if not elements:
            return

        if tagging == '__taggings__' or tagging == '__all__':
            rv = {}
        else:
            rv = []

        # searching what elements should be match
        for info, ts in elements:
            info = unpackb(info)
            if tagging == '__taggings__':
                rv[ts] = list(info.keys())
            elif tagging == '__all__':
                rv[ts] = info
            elif tagging in info:
                if ret_whold:
                    rv.append((info, ts))
                else:
                    rv.append((info[tagging], ts))

        return rv

    def inc_coll_cache_set(self, coll, field, value):
        key = self.inc_coll_cache_fmt.format(name=coll.name)
        self.rdb.hset(key, field, packb(value))

    def inc_coll_caches_get(self, coll, *fields):
        """
        :ret: return [] if no data exists. Normal structure is:
                [value1, value2, ..., valueN]
        """
        if not fields:
            return []

        key = self.inc_coll_cache_fmt.format(name=coll.name)
        rv = self.rdb.hmget(key, *fields)
        # print('inc_coll_caches_get - ', rv)
        # print('inc_coll_caches_get After - ', [unpackb(r) for r in rv if r])
        return [unpackb(r) for r in rv if r]

    def inc_coll_caches_del(self, coll, *fields):
        key = self.inc_coll_cache_fmt.format(name=coll.name)
        return self.rdb.hdel(key, *fields)

    def uniq_count_coll_cache_set(self, coll, ts, tagging, values):
        """
        :param values: should be a iterable object contain members
        """
        values = {packb(v) for v in values}
        key_fmt = self.unique_count_coll_cache_fmt
        key = key_fmt.format(name=coll.name, tagging=tagging, ts=ts)
        return self.rdb.sadd(key, *values)

    def uniq_count_coll_cache_get(self, coll, tagging, timestamps, count_only=False):
        key_fmt = self.unique_count_coll_cache_fmt
        rv = []
        for ts in timestamps:
            key = key_fmt.format(name=coll.name, tagging=tagging, ts=ts)
            if count_only:
                count = self.rdb.scard(key)
                rv.append(count)
            else:
                members = self.rdb.smembers(key)
                rv.append({unpackb(m) for m in members})
        return rv

    def uniq_count_coll_cache_pop(self, coll, tagging, timestamps, number):
        """
        :note: Redis `SPOP key [count]` command, The count argument will be
               available in a later version and is not available
               in 2.6, 2.8, 3.0.
               Now use SRANDMEMBER and SREM commands to mimic the effect of
               SPOP count.
        """
        key_fmt = self.unique_count_coll_cache_fmt
        rv = []
        for ts in timestamps:
            key = key_fmt.format(name=coll.name, tagging=tagging, ts=ts)
            # :: srandmember + srem == spop(key, number)
            members = self.rdb.srandmember(key, number)
            self.rdb.srem(key, *members)
            rv.append({unpackb(m) for m in members})
        return rv

    def uniq_count_coll_cache_del(self, coll, tagging, timestamps):
        keys = self._gen_count_keys(coll.name, tagging,
                                    'unique_count', timestamps)
        return self.rdb.delete(*keys)

    def sorted_count_coll_cache_set(self, coll, ts, tagging, values):
        """
        :param values: should be a dict of <member: score> pair
        """
        key_fmt = self.sorted_count_coll_cache_fmt
        key = key_fmt.format(name=coll.name, tagging=tagging, ts=ts)
        add_val = []
        for member, score in values.items():
            add_val.append(score)
            add_val.append(packb(member))
        return self.rdb.zadd(key, *add_val)

    def sorted_count_coll_cache_get(self, coll, tagging, timestamps, topN=None):
        key_fmt = self.sorted_count_coll_cache_fmt
        rv = []
        for ts in timestamps:
            key = key_fmt.format(name=coll.name, tagging=tagging, ts=ts)
            if topN:
                elements = self.rdb.zrange(key, -topN, -1, withscores=True)
            else:
                elements = self.rdb.zrange(key, 0, -1, withscores=True)
            rv.append([(unpackb(member), score) for member, score in elements])
        # import pprint
        # pprint.pprint(rv)
        return rv

    def sorted_count_coll_cache_del(self, coll, tagging, timestamps):
        keys = self._gen_count_keys(coll.name, tagging,
                                    'sorted_count', timestamps)
        return self.rdb.delete(*keys)

    def _gen_count_keys(self, name, tagging, cachetype, timestamps):
        if cachetype == 'unique_count':
            key_fmt = self.unique_count_coll_cache_fmt
        elif cachetype == 'sorted_count':
            key_fmt = self.sorted_count_coll_cache_fmt

        keys = []
        for ts in timestamps:
            k = key_fmt.format(name=name, tagging=tagging, ts=ts)
            keys.append(k)

        return keys
# need: a list of changesets with their owners and extents that gets built up in redis
# redis wants: a geofenced channel with a list of changeset ids in it, potentially of limited length.
# changesets will build slowly over time, not using the API's bbox support because it's too blunt.
# redis structure for a changeset - ?
# ways: ask the API for their extent? keep them around with a timeout?

redis = StrictRedis()

for changeset_id in sorted(changesets):
    #
    # Delete saved changeset bounding boxes, because they've probably changed.
    #
    changeset_key = 'changeset-' + changeset_id

    redis.hdel(changeset_key, 'min_lat')
    redis.hdel(changeset_key, 'min_lon')
    redis.hdel(changeset_key, 'max_lat')
    redis.hdel(changeset_key, 'max_lon')

for node in nodes:
    #
    # Save nodes to redis hashes under "node-id" keys, with keys "lat", "lon".
    # Also add node keys to associated changeset redis set.
    #
    pipe = redis.pipeline(True)
    node_key = 'node-%(id)s' % node.attrib
    change_items_key = 'changeset-%(changeset)s-items' % node.attrib
    
    osm.remember_node(pipe, node.attrib)
Beispiel #32
0
class RedisUtil:
    def __init__(self):
        self.redishanndle = StrictRedis(
            host=rediscommon.redis_link_host,
            port=rediscommon.redis_link_port,
            db=rediscommon.redis_link_db,
            password=rediscommon.redis_link_password)

    pass

    def queuelpush(self, json_str):
        self.redishanndle.lpush(rediscommon.agent_redis_queue_key, json_str)

    pass

    def queuelpop(self):
        return self.redishanndle.lpop(rediscommon.agent_redis_queue_key)

    pass

    def queuerpush(self, json_str):
        self.redishanndle.rpush(rediscommon.agent_redis_queue_key, json_str)

    pass

    def queuerpop(self):
        return self.redishanndle.rpop(rediscommon.agent_redis_queue_key)

    pass

    def hashset(self, field, value):
        self.redishanndle.hset(rediscommon.agent_redis_hash_key, field, value)

    pass

    def hashget(self, field):
        return self.redishanndle.hget(rediscommon.agent_redis_hash_key, field)

    pass

    def hashexists(self, field):
        return self.redishanndle.hexists(rediscommon.agent_redis_hash_key,
                                         field)

    pass

    def hashdel(self, field):
        return self.redishanndle.hdel(rediscommon.agent_redis_hash_key, field)

    pass

    def hashexistsprint(self):
        print(self.redishanndle.hkeys(rediscommon.agent_redis_hash_key))

    pass

    #向有序集合添加一个或多个成员,或者更新已存在成员的分数
    def sortedsetZADD(self, score, member):
        adddata = {member: score}
        self.redishanndle.zadd(rediscommon.agent_redis_sortedset_key, adddata)

    pass

    #获取有序集合的成员数
    def sortedsetZCARD(self):
        return self.redishanndle.zcard(rediscommon.agent_redis_sortedset_key)

    pass

    #移除有序集合中的一个或多个成员
    def sortedsetZREM(self, member):
        self.redishanndle.zrem(rediscommon.agent_redis_sortedset_key, member)

    pass

    #通过索引区间返回有序集合成指定区间内的成员
    def sortedsetZRANGE(self, start, stop):
        returndata = []
        datalist = self.redishanndle.zrange(
            rediscommon.agent_redis_sortedset_key, start, stop)
        for data in datalist:
            returndata.append(str(data, 'utf-8'))
        return returndata

    pass

    #返回有序集合中指定成员的索引
    def sortedsetZRANK(self, member):
        return self.redishanndle.zrank(rediscommon.agent_redis_sortedset_key,
                                       member)

    pass

    #返回有序集中,成员的分数值
    def sortedsetZSCORE(self, member):
        return self.redishanndle.zscore(rediscommon.agent_redis_sortedset_key,
                                        member)

    pass

    #返回有序集中指定区间内的成员,通过索引,分数从高到底
    def sortedsetZREVRANGE(self, start, stop):
        returndata = []
        datalist = self.redishanndle.zrevrange(
            rediscommon.agent_redis_sortedset_key, start, stop)
        for data in datalist:
            returndata.append(str(data, 'utf-8'))
        return returndata

    pass

    #返回有序集中 最前面的第几个
    def sortedsetGETTOP(self, number):
        returndata = []
        sum = self.redishanndle.zcard(rediscommon.agent_redis_sortedset_key)
        datalist = self.redishanndle.zrevrange(
            rediscommon.agent_redis_sortedset_key, sum - number, sum)
        for data in datalist:
            returndata.append(str(data, 'utf-8'))
        return returndata

    pass

    #按分数返回一个成员范围的有序集合。
    def sortedsetZRANGEBYSCORE(
        self,
        min,
        max,
        start=None,
        num=None,
    ):
        returndata = []
        datalist = self.redishanndle.zrangebyscore(
            rediscommon.agent_redis_sortedset_key, min, max, start, num)
        for data in datalist:
            returndata.append(str(data, 'utf-8'))
        return returndata

    pass

    #计算在有序集合中指定区间分数的成员数
    def sortedsetZCOUNT(self, min, max):
        return self.redishanndle.zcount(rediscommon.agent_redis_sortedset_key,
                                        min, max)

    pass
Beispiel #33
0
# 根据键获取值
print(redis.hget('h', '1').decode('utf-8'))

# 根据多个键获取多个值
print(redis.hmget('h', ['1', 'nx_data']))

# 将对应键的值增加 非整型报错 增量非整型也报错 默认为1
print(redis.hincrby('h', 'nx_data', amount=1))

# 将对应键的值增加 允许浮点型
print(redis.hincrbyfloat('h', 'nx_data1', amount=1.5))

# 是否存在值
print(redis.hexists('h', 'jj'))
print(redis.hexists('h', '1'))

# 删除 不存在就返回0  返回删除的数量
print(redis.hdel('h', ['1']))

# 哈希表的长度
print(redis.hlen('h'))

# 获取所有的键名
print(redis.hkeys('h'))

# 获取所有的值
print(redis.hvals('h'))

# 获取所有键值对
print(redis.hgetall('h'))
Beispiel #34
0
class Redis(object):
    def __init__(self, host: str = "localhost", port: int = 6379, db: int = 0, password: str = None):
        self.redis = StrictRedis(host=host, port=port, db=db, password=password)

    @staticmethod
    def help():
        """
        打印帮助信息
        """
        print("open in browser => https://cloud.tencent.com/developer/article/1151834")


    def increase(self, name, amount=1) -> int:
        """
        增加操作
        :param name: 名字
        :param amount: 增加的值,默认1
        :return: 增加后的值
        """
        return self.redis.incr(name, amount)

    def decrease(self, name, amount=1) -> int:
        """
        减少操作
        :param name: 名字
        :param amount: 减少的值,默认1
        :return: 减少后的值
        """
        return self.redis.decr(name, amount)

    def set_keys(self, **kwargs):
        """
        以字符串保存
        :param kwargs: 要插入的字符串键值对
        """
        self.redis.mset(kwargs)

    def get_keys(self, *string_name, decode="utf-8") -> list:
        """
        返回字符串的字,解码
        :param string_name: 要查询的字符串名
        :param decode: 是否返回解码后的字符串,默认是
        """
        if decode:
            return decode_list(self.redis.mget(string_name), decode)
        return self.redis.mget(string_name)

    def add_list_tail(self, list_name, *value) -> int:
        """
        从后追加进列表
        :param list_name: 列表名
        :value: 值
        :return: 列表大小
        """
        return self.redis.rpush(list_name, *value)

    def add_list_head(self, list_name, *value) -> int:
        """
        从后追加进列表
        :param list_name: 列表名
        :value: 值
        :return: 列表大小
        """
        return self.redis.lpush(list_name, *value)

    def get_list_length(self, list_name) -> int:
        """
        返回列表长
        :param list_name: 列表名
        :return: 列表长度
        """
        return self.redis.llen(list_name)

    def pop_list_head(self, list_name, decode="utf-8") -> str:
        """
        弹出列表头
        :param list_name: 列表名
        :param decode: 是否解码,以和中方式解码
        :return: 返回列表第一个值
        """
        if decode:
            return self.redis.rpop(list_name).decode(decode)
        return self.redis.rpop(list_name)

    def pop_list_tail(self, list_name, decode="utf-8") -> str:
        """
        弹出列表尾
        :param list_name: 列表名
        :param decode: 是否解码,以何种方式解码
        :return: 返回列表最后一个值
        """
        if decode:
            self.redis.lpop(list_name).decode(decode)
        return self.redis.lpop(list_name)

    def get_list_value(self, list_name, start=0, end=-1, decode="utf-8") -> list:
        """
        从列表中获取元素
        :param list_name: 列表名
        :param start: 起始下标
        :param end: 截至下标
        :param decode: 是否解码,以何种方式解码
        :return: 返回[star, end]之间的值
        """
        if decode:
            return decode_list(self.redis.lrange(list_name, start, end), decode)
        return self.redis.lrange(list_name, start, end)

    def set_list_value(self, list_name, index, value):
        """
        给列表指定下标赋值,越界报错
        :param list_name: 列表名
        :param index: 下标
        :param value: 新值
        """
        self.redis.lset(list_name, index, value)

    def remove_list_item_by_value(self, list_name, value, count=1) -> int:
        """
        删除名为list_name列表中值为value的元素count个
        :param list_name: 列表名
        :param value: 值
        :param count: 待删除的个数
        :return: 删除的个数
        """
        return self.redis.lrem(list_name, count, value)

    def add_to_set(self, set_name, *values) -> int:
        """
        向集合中增加元素
        :param set_name: 集合名
        :param values: 数据
        :return: 返回插入的个数
        """
        return self.redis.sadd(set_name, *values)

    def remove_set_item_by_value(self, set_name, *values):
        """
        向集合中删除元素
        :param set_name: 集合名
        :param values: 要删除的胡数据
        :return: 返回删除的个数
        """
        return self.redis.srem(set_name, *values)

    def get_set_length(self, set_name):
        """
        返回集合长度
        :param set_name: 集合名
        :return: 集合长度
        """
        return self.redis.scard(set_name)

    def pop_set_random(self, set_name, count=1, decode="utf-8") -> list:
        """
        从集合中随机弹出count个值
        :param set_name: 集合名
        :param count: 弹出的个数
        :param decode: 是否解码,以及编码方式
        :return: 集合中的值
        """
        if decode:
            return decode_list(self.redis.spop(set_name, count), decode)
        return self.redis.spop(set_name, count)

    def inter_set(self, set_names: list, decode="utf-8") -> set:
        """
        求列表中的集合的交集
        :param set_names: 集合名列表
        :param decode: 是否对返回结果解码,以及解码方式
        :return: 交集,集合类型
        """
        if decode:
            return set(decode_list(self.redis.sinter(set_names), decode))
        return self.redis.sinter(set_names)

    def union_set(self, set_names: list, decode="utf-8") -> set:
        """
        求列表中的集合的并集
        :param set_names: 集合名列表
        :param decode: 是否对返回结果解码,以及解码方式
        :return: 并集,集合类型
        """
        if decode:
            return set(decode_list(self.redis.sunion(set_names), decode))
        return self.redis.sunion(set_names)

    def diff_set(self, set_names: list, decode="utf-8") -> set:
        """
        求列表中的集合的差集
        :param set_names: 集合名列表
        :param decode: 是否对返回结果解码,以及解码方式
        :return: 差集,集合类型
        """
        if decode:
            return set(decode_list(self.redis.sdiff(set_names), decode))
        return self.redis.sdiff(set_names)

    def get_set_all(self, set_name, decode="utf-8") -> set:
        """
        返回集合中的所有元素
        :param set_name: 集合名列表
        :param decode: 是否对返回结果解码,以及解码方式
        :return: 差集,集合类型
        """
        if decode:
            return set(decode_list(self.redis.smembers(set_name), decode))
        return self.redis.smembers(set_name)

    def get_set_random(self, set_name, count=1, decode="utf-8") -> list:
        """
        从集合中随机获取count个值
        :param set_name: 集合名
        :param count: 弹出的个数
        :param decode: 是否解码,以及编码方式
        :return: 集合中的值
        """
        if decode:
            return decode_list(self.redis.srandmember(set_name, count), decode)
        return self.redis.srandmember(set_name, count)

    def add_to_zset(self, zset_name, **map):
        """
        向有序集合中加入元素
        :param zset_name: 有序集合名
        :param map: 键值对,key为插入的元素值,value为权重int类型
        """
        self.redis.zadd(zset_name, map)

    def remove_zset_item_by_value(self, zset_name, *value):
        """
        删除有序集合中名为value的元素
        :param zset_name: 有序集合名
        :param value: 要删除的值
        """
        self.redis.zrem(zset_name, *value)

    def increase_zset_item_by_value(self, zset_name, value, amount=1):
        """
        将有序集合zset_name中值为value的权重加amount
        :param zset_name: 有序集合名
        :param value: 要增加权重的值
        :param amount: 增加的权重,负数为减
        """
        self.redis.zincrby(zset_name, amount, value)

    def item_rank_in_zset(self, zset_name, value, reverse=False) -> int:
        """
        返回value在zset中的排名
        :param zset_name: 有序集合名
        :param value: 值
        :param reverse: False -> 从小到大  True -> 从大到小
        :return: 返回value在zset中的排名
        """
        if reverse:
            return self.redis.zrevrank(zset_name, value)
        return self.redis.zrank(zset_name, value)

    def get_zset_value_by_rank(self, zset_name, start=0, end=-1, withscores=False, decode="utf-8",
                               reverse=False) -> list:
        """
        从有序集合中获取下标在指定范围的值
        :param zset_name: 有序集合名
        :param start: 开始下标
        :param end: 结束下标
        :param withscores: 是否带有权值
        :param decode: 返回结果是否解码
        :param reverse: False -> 从小到大 True -> 从大到小
        :return: 从有序集合中获取下标在指定范围的值,list类型
        """
        if withscores:
            if decode:
                return decode_list_tuple(self.redis.zrange(zset_name, start, end, reverse, withscores), decode)
            return self.redis.zrange(zset_name, start, end, reverse, withscores)
        else:
            if decode:
                return decode_list(self.redis.zrange(zset_name, start, end, reverse, withscores), decode)
            return self.redis.zrange(zset_name, start, end, reverse, withscores)

    def get_zset_value_by_score(self, zset_name, min, max, start=None, num=None, withscores=False,
                                decode="utf-8", ) -> list:
        """
        从有序集合中获取权值在指定范围的值
        :param zset_name: 有序集合名
        :param min: 最小权值
        :param max: 最大权值
        :param start: 从哪个下标开始查找
        :param num: 查找个数 start 必须 和 num同时设定
        :param withscores: 是否带有权值
        :param decode: 返回结果是否解码
        :param reverse: False -> 从小到大 True -> 从大到小
        :return: 有序集合中获取权值在指定范围的值,list类型
        """
        if withscores:
            if decode:
                return decode_list_tuple(self.redis.zrangebyscore(zset_name, min, max, start, num, withscores), decode)
            return self.redis.zrangebyscore(zset_name, min, max, start, num, withscores)
        else:
            if decode:
                return decode_list(self.redis.zrangebyscore(zset_name, min, max, start, num, withscores), decode)
            return self.redis.zrangebyscore(zset_name, min, max, start, num, withscores)

    def count_zset_value_by_score(self, zset_name, min, max) -> int:
        """
        统计在权值在区间内的数量
        :param zset_name: 有序集合名
        :param min: 最小值
        :param max: 最大值
        :return: 返回数量
        """
        return self.redis.zcount(zset_name, min, max)

    def get_zset_length(self, zset_name) -> int:
        """
        返回zset长度
        :param zset_name: 有序集合名
        :return: 返回长度
        """
        return self.redis.zcard(zset_name)

    def remove_zset_item_by_rank(self, zset_name, start, end):
        """
        从有序集合中删除下标在指定范围中的值
        :param zset_name: 有序集合名
        :param start: 开始排名
        :param end: 结束排名
        """
        self.redis.zremrangebyrank(zset_name, start, end)

    def remove_zset_item_by_score(self, zset_name, min, max):
        """
        从有序集合中删除权值在指定范围中的值
        :param zset_name: 有序集合名
        :param min: 最小值
        :param max: 最大值
        """
        self.redis.zremrangebyscore(zset_name, min, max)

    def add_to_map(self, map_name, **kwargs) -> int:
        """
        向映射中添加键值对
        :param map_name: 映射名
        :param kwargs: 要添加的键值对
        :return: 增加的键值对的个数
        """
        self.redis.hmset(map_name, kwargs)
        return len(kwargs)

    def remove_map_item_by_keys(self, map_name, *keys) -> int:
        """
        删除映射中键为keys中的元素
        :param map_name: 映射名
        :param keys: 要删除的键的list
        :return: 删除的个数
        """
        self.redis.hdel(map_name, *keys)
        return len(keys)

    def update_map_item(self, map_name, **kwargs) -> int:
        """
        修改映射键值对
        :param map_name: 映射名
        :param kwargs: 新的键值对,如果不存在则添加
        :return: 修改的个数
        """
        for key, value in kwargs.items():
            self.redis.hsetnx(map_name, key, value)
        return len(kwargs)

    def get_value_from_map_by_keys(self, map_name, *keys, decode="utf-8") -> list:
        """
        从映射中获取对应key的value
        :param map_name: 映射名
        :param keys: 要获取的key
        :param decode: 返回结果是否解码,以及以何种方式解码
        :return: 返回对应的value
        """
        if decode:
            return decode_list(self.redis.hmget(map_name, keys), decode)
        return self.redis.hmget(map_name, keys)

    def get_map_length(self, map_name) -> int:
        """
        获取映射的元素个数
        :param map_name: 映射名
        :return: 元素个数
        """
        return self.redis.hlen(map_name)

    def get_map_all_keys(self, map_name, decode="utf-8") -> list:
        """
        返回映射所有的key
        :param map_name: 映射名
        :param decode: 返回结果是否解码,以及以何种方式解码
        :return: 映射key列表
        """
        if decode:
            return decode_list(self.redis.hkeys(map_name), decode)
        return self.redis.hkeys(map_name)

    def get_map_all_values(self, map_name, decode="utf-8") -> list:
        """
        返回映射所有的value
        :param map_name: 映射名
        :param decode: 返回结果是否解码,以及以何种方式解码
        :return: 映射value列表
        """
        if decode:
            return decode_list(self.redis.hvals(map_name), decode)
        return self.redis.hvals(map_name)
Beispiel #35
0
def unset_running(name: str) -> None:
    r = StrictRedis(unix_socket_path=get_socket_path('lookup'), db=1, decode_responses=True)
    r.hdel('running', name)
Beispiel #36
0
class KartonBackend:
    def __init__(self, config):
        self.config = config
        self.redis = StrictRedis(
            host=config["redis"]["host"],
            port=int(config["redis"].get("port", 6379)),
            decode_responses=True,
        )
        self.minio = Minio(
            config["minio"]["address"],
            access_key=config["minio"]["access_key"],
            secret_key=config["minio"]["secret_key"],
            secure=bool(int(config["minio"].get("secure", True))),
        )

    @property
    def default_bucket_name(self) -> str:
        return self.config.minio_config["bucket"]

    @staticmethod
    def get_queue_name(identity: str, priority: TaskPriority) -> str:
        """
        Return Redis routed task queue name for given identity and priority

        :param identity: Karton service identity
        :param priority: Queue priority (TaskPriority enum value)
        :return: Queue name
        """
        return f"karton.queue.{priority.value}:{identity}"

    @staticmethod
    def get_queue_names(identity: str) -> List[str]:
        """
        Return all Redis routed task queue names for given identity,
        ordered by priority (descending). Used internally by Consumer.

        :param identity: Karton service identity
        :return: List of queue names
        """
        return [
            identity,  # Backwards compatibility (2.x.x)
            KartonBackend.get_queue_name(identity, TaskPriority.HIGH),
            KartonBackend.get_queue_name(identity, TaskPriority.NORMAL),
            KartonBackend.get_queue_name(identity, TaskPriority.LOW),
        ]

    @staticmethod
    def serialize_bind(bind: KartonBind) -> str:
        """
        Serialize KartonBind object (Karton service registration)

        :param bind: KartonBind object with bind definition
        :return: Serialized bind data
        """
        return json.dumps(
            {
                "info": bind.info,
                "version": bind.version,
                "filters": bind.filters,
                "persistent": bind.persistent,
            },
            sort_keys=True,
        )

    @staticmethod
    def unserialize_bind(identity: str, bind_data: str) -> KartonBind:
        """
        Deserialize KartonBind object for given identity.
        Compatible with Karton 2.x.x and 3.x.x

        :param identity: Karton service identity
        :param bind_data: Serialized bind data
        :return: KartonBind object with bind definition
        """
        bind = json.loads(bind_data)
        if isinstance(bind, list):
            # Backwards compatibility (v2.x.x)
            return KartonBind(
                identity=identity,
                info=None,
                version="2.x.x",
                persistent=not identity.endswith(".test"),
                filters=bind,
            )
        return KartonBind(
            identity=identity,
            info=bind["info"],
            version=bind["version"],
            persistent=bind["persistent"],
            filters=bind["filters"],
        )

    def get_bind(self, identity: str) -> KartonBind:
        """
        Get bind object for given identity

        :param identity: Karton service identity
        :return: KartonBind object
        """
        return self.unserialize_bind(
            identity, self.redis.hget(KARTON_BINDS_HSET, identity))

    def get_binds(self) -> List[KartonBind]:
        """
        Get all binds registered in Redis

        :return: List of KartonBind objects for subsequent identities
        """
        return [
            self.unserialize_bind(identity, raw_bind) for identity, raw_bind in
            self.redis.hgetall(KARTON_BINDS_HSET).items()
        ]

    def register_bind(self, bind: KartonBind) -> Optional[KartonBind]:
        """
        Register bind for Karton service and return the old one

        :param bind: KartonBind object with bind definition
        :return: Old KartonBind that was registered under this identity
        """
        with self.redis.pipeline(transaction=True) as pipe:
            pipe.hget(KARTON_BINDS_HSET, bind.identity)
            pipe.hset(KARTON_BINDS_HSET, bind.identity,
                      self.serialize_bind(bind))
            old_serialized_bind, _ = pipe.execute()

        if old_serialized_bind:
            return self.unserialize_bind(bind.identity, old_serialized_bind)
        else:
            return None

    def unregister_bind(self, identity: str) -> None:
        """
        Removes bind for identity
        :param bind: Identity to be unregistered
        """
        self.redis.hdel(KARTON_BINDS_HSET, identity)

    def set_consumer_identity(self, identity: str) -> None:
        """
        Sets identity for current Redis connection
        """
        return self.redis.client_setname(identity)

    def get_online_consumers(self) -> Dict[str, List[str]]:
        """
        Gets all online consumer identities

        :return: Dictionary {identity: [list of clients]}
        """
        bound_identities = defaultdict(list)
        for client in self.redis.client_list():
            bound_identities[client["name"]].append(client)
        return bound_identities

    def get_task(self, task_uid: str) -> Optional[Task]:
        """
        Get task object with given identifier

        :param task_uid: Task identifier
        :return: Task object
        """
        task_data = self.redis.get(f"{KARTON_TASK_NAMESPACE}:{task_uid}")
        if not task_data:
            return None
        return Task.unserialize(task_data, backend=self)

    def get_tasks(self, task_uid_list: List[str]) -> List[Task]:
        """
        Get multiple tasks for given identifier list

        :param task_uid_list: List of task identifiers
        :return: List of task objects
        """
        task_list = self.redis.mget([
            f"{KARTON_TASK_NAMESPACE}:{task_uid}" for task_uid in task_uid_list
        ])
        return [
            Task.unserialize(task_data, backend=self)
            for task_data in task_list if task_data is not None
        ]

    def get_all_tasks(self) -> List[Task]:
        """
        Get all tasks registered in Redis

        :return: List with Task objects
        """
        tasks = self.redis.keys(f"{KARTON_TASK_NAMESPACE}:*")
        return [
            Task.unserialize(task_data) for task_data in self.redis.mget(tasks)
            if task_data is not None
        ]

    def register_task(self, task: Task) -> None:
        """
        Register task in Redis.

        Consumer should register only Declared tasks.
        Status change should be done using set_task_status.

        :param task: Task object
        """
        self.redis.set(f"{KARTON_TASK_NAMESPACE}:{task.uid}", task.serialize())

    def set_task_status(self,
                        task: Task,
                        status: TaskState,
                        consumer: Optional[str] = None) -> None:
        """
        Request task status change to be applied by karton-system

        :param task: Task object
        :param status: New task status (TaskState)
        :param consumer: Consumer identity
        """
        self.redis.rpush(
            KARTON_OPERATIONS_QUEUE,
            json.dumps({
                "status": status.value,
                "identity": consumer,
                "task": task.serialize(),
                "type": "operation",
            }),
        )

    def delete_task(self, task: Task) -> None:
        """
        Remove task from Redis

        :param task: Task object
        """
        self.redis.delete(f"{KARTON_TASK_NAMESPACE}:{task.uid}")

    def get_task_queue(self, queue: str) -> List[Task]:
        """
        Return all tasks in provided queue

        :param queue: Queue name
        :return: List with Task objects contained in queue
        """
        task_uids = self.redis.lrange(queue, 0, -1)
        return self.get_tasks(task_uids)

    def get_task_ids_from_queue(self, queue: str) -> List[str]:
        """
        Return all task UIDs in a queue

        :param queue: Queue name
        :return: List with task identifiers contained in queue
        """
        return self.redis.lrange(queue, 0, -1)

    def remove_task_queue(self, queue: str) -> List[Task]:
        """
        Remove task queue with all contained tasks

        :param queue: Queue name
        :return: List with Task objects contained in queue
        """
        pipe = self.redis.pipeline()
        pipe.lrange(queue, 0, -1)
        pipe.delete(queue)
        return self.get_tasks(pipe.execute()[0])

    def produce_unrouted_task(self, task: Task) -> None:
        """
        Add given task to unrouted task (``karton.tasks``) queue

        Task must be registered before with :py:meth:`register_task`

        :param task: Task object
        """
        self.redis.rpush(KARTON_TASKS_QUEUE, task.uid)

    def produce_routed_task(self, identity: str, task: Task) -> None:
        """
        Add given task to routed task queue of given identity

        Task must be registered using :py:meth:`register_task`

        :param identity: Karton service identity
        :param task: Task object
        """
        self.redis.rpush(self.get_queue_name(identity, task.priority),
                         task.uid)

    def consume_queues(self,
                       queues: Union[str, List[str]],
                       timeout: int = 0) -> Optional[Tuple[str, str]]:
        """
        Get item from queues (ordered from the most to the least prioritized)
        If there are no items, wait until one appear.

        :param queues: Redis queue name or list of names
        :param timeout: Waiting for item timeout (default: 0 = wait forever)
        :return: Tuple of [queue_name, item] objects or None if timeout has been reached
        """
        return self.redis.blpop(queues, timeout=timeout)

    def consume_routed_task(self,
                            identity: str,
                            timeout: int = 5) -> Optional[Task]:
        """
        Get routed task for given consumer identity.

        If there are no tasks, blocks until new one appears or timeout is reached.

        :param identity: Karton service identity
        :param timeout: Waiting for task timeout (default: 5)
        :return: Task object
        """
        item = self.consume_queues(
            self.get_queue_names(identity),
            timeout=timeout,
        )
        if not item:
            return None
        queue, data = item
        return self.get_task(data)

    @staticmethod
    def _log_channel(logger_name: Optional[str], level: Optional[str]) -> str:
        return ".".join(
            [KARTON_LOG_CHANNEL, (level or "*").lower(), logger_name or "*"])

    def produce_log(
        self,
        log_record: Dict[str, Any],
        logger_name: str,
        level: str,
    ) -> bool:
        """
        Push new log record to the logs channel

        :param log_record: Dict with log record
        :param logger_name: Logger name
        :param level: Log level
        :return: True if any active log consumer received log record
        """
        return (self.redis.publish(self._log_channel(logger_name, level),
                                   json.dumps(log_record)) > 0)

    def consume_log(
        self,
        timeout: int = 5,
        logger_filter: Optional[str] = None,
        level: Optional[str] = None,
    ) -> Iterator[Optional[Dict[str, Any]]]:
        """
        Subscribe to logs channel and yield subsequent log records
        or None if timeout has been reached.

        If you want to subscribe only to a specific logger name
        and/or log level, pass them via logger_filter and level arguments.

        :param timeout: Waiting for log record timeout (default: 5)
        :param logger_filter: Filter for name of consumed logger
        :param level: Log level
        :return: Dict with log record
        """
        with self.redis.pubsub() as pubsub:
            pubsub.psubscribe(self._log_channel(logger_filter, level))
            while pubsub.subscribed:
                item = pubsub.get_message(ignore_subscribe_messages=True,
                                          timeout=timeout)
                if item and item["type"] == "pmessage":
                    body = json.loads(item["data"])
                    if "task" in body and isinstance(body["task"], str):
                        body["task"] = json.loads(body["task"])
                    yield body
                yield None

    def increment_metrics(self, metric: KartonMetrics, identity: str) -> None:
        """
        Increments metrics for given operation type and identity

        :param metric: Operation metric type
        :param identity: Related Karton service identity
        """
        self.redis.hincrby(metric.value, identity, 1)

    def upload_object(
        self,
        bucket: str,
        object_uid: str,
        content: Union[bytes, BinaryIO],
        length: int = None,
    ) -> None:
        """
        Upload resource object to underlying object storage (Minio)

        :param bucket: Bucket name
        :param object_uid: Object identifier
        :param content: Object content as bytes or file-like stream
        :param length: Object content length (if file-like object provided)
        """
        if isinstance(content, bytes):
            length = len(content)
            content = BytesIO(content)
        self.minio.put_object(bucket, object_uid, content, length)

    def upload_object_from_file(self, bucket: str, object_uid: str,
                                path: str) -> None:
        """
        Upload resource object file to underlying object storage

        :param bucket: Bucket name
        :param object_uid: Object identifier
        :param path: Path to the object content
        """
        self.minio.fput_object(bucket, object_uid, path)

    def get_object(self, bucket: str, object_uid: str) -> HTTPResponse:
        """
        Get resource object stream with the content.

        Returned response should be closed after use to release network resources.
        To reuse the connection, it's required to call `response.release_conn()`
        explicitly.

        :param bucket: Bucket name
        :param object_uid: Object identifier
        :return: Response object with content
        """
        return self.minio.get_object(bucket, object_uid)

    def download_object(self, bucket: str, object_uid: str) -> bytes:
        """
        Download resource object from object storage.

        :param bucket: Bucket name
        :param object_uid: Object identifier
        :return: Content bytes
        """
        reader = self.minio.get_object(bucket, object_uid)
        try:
            return reader.read()
        finally:
            reader.release_conn()
            reader.close()

    def download_object_to_file(self, bucket: str, object_uid: str,
                                path: str) -> None:
        """
        Download resource object from object storage to file

        :param bucket: Bucket name
        :param object_uid: Object identifier
        :param path: Target file path
        """
        self.minio.fget_object(bucket, object_uid, path)

    def list_objects(self, bucket: str) -> List[str]:
        """
        List identifiers of stored resource objects

        :param bucket: Bucket name
        :return: List of object identifiers
        """
        return [
            object.object_name for object in self.minio.list_objects(bucket)
        ]

    def remove_object(self, bucket: str, object_uid: str) -> None:
        """
        Remove resource object from object storage

        :param bucket: Bucket name
        :param object_uid: Object identifier
        """
        self.minio.remove_object(bucket, object_uid)

    def check_bucket_exists(self, bucket: str, create: bool = False) -> bool:
        """
        Check if bucket exists and optionally create it if it doesn't.

        :param bucket: Bucket name
        :param create: Create bucket if doesn't exist
        :return: True if bucket exists yet
        """
        if self.minio.bucket_exists(bucket):
            return True
        if create:
            self.minio.make_bucket(bucket)
        return False
Beispiel #37
0
class RedisLRU(object):
    def __init__(self, redis=None, **kwargs):
        if redis is not None:
            self._redis = redis
        else:
            self._redis = Redis(**kwargs)
        self.namespaces = {"default": 10000}

    def setup_namespace(self, namespace, size):
        """Set the LRU Size for a namespace.
        """
        self.namespaces[namespace] = int(size)

    def _serialize(self, s):
        # return json.dumps(s)
        return s

    def _unserialize(self, s):
        # s = s.decode("utf-8")
        # return json.loads(s)
        return s

    def _size(self, namespace):
        return self.namespaces[namespace]

    def _hit_store(self, namespace):
        if namespace not in self.namespaces:
            raise KeyError("invalid namespace")
        return "cache_keys_{}".format(namespace)

    def _value_store(self, namespace):
        if namespace not in self.namespaces:
            raise KeyError("invalid namespace")
        return "cache_values_{}".format(namespace)

    def _expire_old(self, namespace):
        hits = self._hit_store(namespace)
        size = self._size(namespace)
        count = self._redis.zcard(hits)
        if count >= size:
            values = self._value_store(namespace)
            items = self._redis.zrange(hits, 0, count - size)
            logger.error(items)
            self._redis.zremrangebyrank(hits, 0, count - size)
            self._redis.hdel(values, *items)

    def clear(self, namespace="default"):
        """Clear the Cache.
        """
        hits = self._hit_store(namespace)
        values = self._value_store(namespace)
        self._redis.delete(hits, values)

    def clearAll(self):
        """Clear all known namespaces.
        """
        for k in self.namespaces.iterkeys():
            self.clear(k)

    def store(self, key, value, namespace="default"):
        """Store a key value pair in cache.
        This will not update an existing item.
        """
        values = self._value_store(namespace)
        if not self._redis.hexists(values, key):
            hits = self._hit_store(namespace)
            self._expire_old(namespace)
            self._redis.hset(values, key, self._serialize(value))
            self._redis.zadd(hits, time.time(), key)
        else:
            hits = self._hit_store(namespace)
            self._redis.hset(values, key, self._serialize(value))
            self._redis.zadd(hits, time.time(), key)

    def get(self, key, namespace="default"):
        """Get a value from the cache.
        returns none if the key is not found.
        """
        values = self._value_store(namespace)
        value = self._redis.hget(values, key)
        if value:
            hits = self._hit_store(namespace)
            self._redis.zadd(hits, time.time(), key)
            return self._unserialize(value)
        return None

    def expire(self, key, namespace="default"):
        """Expire (invalidate) a key from the cache.
        """
        values = self._value_store(namespace)
        if self._redis.hexists(values, key):
            hits = self._hit_store(namespace)
            self._redis.hdel(values, key)
            self._redis.zrem(hits, key)
Beispiel #38
0
class RedisUtils(object):
    def __init__(self, host, port, db, password=None):
        if password is not None:
            self._client = StrictRedis(host=host,
                                       port=port,
                                       db=db,
                                       password=password)
        else:
            self._client = StrictRedis(host=host, port=port, db=db)

    def common_utils(self):
        """
        通用操作
        :return:
        """
        pass

    def collection_utils(self):
        """
        统计操作
        :return:
        """
        pass

    def string_utils(self):
        """
        字符串操作
        :return:
        """
        str_name = "str"
        str_value = "str_value"
        int_name = "number"
        int_value = 25
        int_str_name = "num_to_str"
        int_str_value = 10000
        int_max_name = "max_number"
        int_max_value = 2444449999999999999999999
        int_min_name = "min_number"
        int_min_value = -1111111111111111111111111
        float_name = "float_number"
        float_value = 23.45
        result = self._client.set(str_name, str_value)
        result_len = self._client.strlen(str_name)
        print("String Set key:", str_name, " value:", str_value, " result:",
              result, " len:", result_len)
        result = self._client.set(int_name, int_value)
        result_len = self._client.strlen(int_name)
        print("String Set key:", int_name, " value:", int_value, " result:",
              result, " len:", result_len)
        result = self._client.set(int_str_name, int_str_value)
        result_len = self._client.strlen(int_str_name)
        print("String Set key:", int_str_name, " value:", int_str_value,
              " result:", result, " len:", result_len)
        result = self._client.set(int_max_name, int_max_value)
        result_len = self._client.strlen(int_max_name)
        print("String Set key:", int_max_name, " value:", int_max_value,
              " result:", result, " len:", result_len)
        result = self._client.set(int_min_name, int_min_value)
        result_len = self._client.strlen(int_min_name)
        print("String Set key:", int_min_name, " value:", int_min_value,
              " result:", result, " len:", result_len)
        result = self._client.set(float_name, float_value)
        result_len = self._client.strlen(float_name)
        print("String Set key:", float_name, " value:", float_value,
              " result:", result, " len:", result_len)

        str_dict = {"str_key": "keyvalue", "int_key": 234, "float_key": 234.09}
        result = self._client.mset(str_dict)
        print("String MSet dict:", str_dict, " result:", result)

        null_str_name = ""
        null_str_value = self._client.get(null_str_name)
        print("String Get key:", null_str_name, " value:", null_str_value)
        dest_str_value = self._client.get(str_name)
        print("String Get key:", str_name, " value", dest_str_value, " type:",
              type(dest_str_value))
        dest_int_value = self._client.get(int_name)
        print("String Get key:", int_name, " value", dest_int_value, " type:",
              type(dest_int_value))
        multi_get_name = ["str_key", "int_key", "float_key"]
        result = self._client.mget(multi_get_name)
        result_dict = dict(zip(multi_get_name, result))
        print("String MGet key:", multi_get_name, " values:", result, " type:",
              type(result), " dict:", result_dict)

        ### 自增 自减 支持负数增减
        incr_name = "incr_name"
        incr_count = 2
        result = self._client.incr(incr_name, incr_count)
        print("String Incr key:", incr_name, "incr_count:", incr_count,
              " result:", result)
        incr_count = -2
        result = self._client.incr(incr_name, incr_count)
        print("String Incr key:", incr_name, "incr_count:", incr_count,
              " result:", result)
        decr_name = "decr_name"
        decr_count = -2
        result = self._client.decr(decr_name, decr_count)
        print("String Decr key:", decr_name, "incr_count:", decr_count,
              " result:", result)
        decr_count = 2
        result = self._client.decr(decr_name, decr_count)
        print("String Decr key:", decr_name, "incr_count:", decr_count,
              " result:", result)

    def list_utils(self):
        not_existed_list_name = "not exist list name"
        list_name = "list_key"
        list_str_value = "list value"
        list_int_value = 234
        # O(1)
        result = self._client.rpush(list_name, list_str_value, list_int_value)
        print("List RPUSH key:", list_name, "value:", list_int_value,
              list_str_value, "result:", result)
        list_value = ("list_value_1", "list_value_2", 234)
        # O(1)
        result = self._client.rpush(list_name, *list_value)
        print("List RPUSH key:", list_name, "value:", list_value, "result:",
              result)
        # O(X)
        result = self._client.rpushx(list_name, list_value)
        print("List RPUSHX key:", list_name, "value:", list_value, "result:",
              result)
        result = self._client.rpushx(not_existed_list_name, list_value)
        print("List RPUSHX key:", not_existed_list_name, "value:", list_value,
              "result:", result)

        # O(1)
        result = self._client.lpop(list_name)
        print("List LPOP key:", list_name, " value:", result)
        # O(1)
        result = self._client.rpop(list_name)
        print("List RPOP key:", list_name, " value:", result)

        # O(n)
        result = self._client.lrem(list_name, 1, 231)
        print("List LREM key:", list_name, "result:", result)
        # O(n)
        lstart = 0
        lend = 2
        result = self._client.ltrim(list_name, lstart, lend)
        print("List LTRIM key:", list_name, " result:", result)

        # O(1)
        result = self._client.llen(list_name)
        print("List LLEN key:", list_name, " len:", result)

        # O(X)
        result = self._client.linsert(list_name, "before", 234, "Insert Value")
        print("List LINSERT key:", list_name, " result:", result)

        lindex = 2  # Start As 0
        # O(X)
        result = self._client.lindex(list_name, lindex)
        print("List LINDEX key:", list_name, " result:", result)

    def set_utils(self):
        """
        集合操作
        分类 社交 标签
        :return:
        """
        set_name = "set_name"
        set_value = ("set_1", "set_2", 3, 4)
        # O(K)
        result = self._client.sadd(set_name, *set_value)
        print("Set SADD key:", set_name, "value:", set_value, " result:",
              result)
        # O(1)
        result = self._client.scard(set_name)
        print("Set SCARD key:", set_name, " result:", result)
        s_find_value = "set_1"
        # O(1)
        result = self._client.sismember(set_name, s_find_value)
        print("Set SISMEMBER key:", set_name, " find_value:", s_find_value,
              " result:", result)

        random_count = 2
        # O(K)
        result = self._client.srandmember(set_name, number=random_count)
        print("Set SRANDOMMEMBER key:", set_name, "result:", result)

        # O(1)
        result = self._client.spop(set_name)
        print("Set SPOP key:", set_name, " result:", result)

        # O(K)
        result = self._client.srem(set_name, *set_value)
        print("Set SREM key:", set_name, "value:", set_value, " result:",
              result)

        set_a_name = "set_a"
        set_a_value = [
            "set_value_1", "set_value_3", "set_value_6", "set_value_9",
            "set_value_10"
        ]
        set_b_name = "set_b"
        set_b_value = [
            "set_value_1", "set_value_3", "set_value_6", "set_value_8",
            "set_value_0"
        ]
        self._client.sadd(set_a_name, *set_a_value)
        self._client.sadd(set_b_name, *set_b_value)
        # O(K)
        result = self._client.sinter(set_a_name, set_b_name)
        print("Set SINTER key:", set_a_name, " key:", set_b_name, " result:",
              result)
        # O(K)
        result = self._client.sunion(set_a_name, set_b_name)
        print("Set SUNION key:", set_a_name, " key:", set_b_name, " result:",
              result)
        # O(K)
        result = self._client.sdiff(set_a_name, set_b_name)
        print("Set SDIFF key:", set_a_name, " key:", set_b_name, " result:",
              result)
        self._client.delete(set_a_name)
        self._client.delete(set_b_name)

    def zset_utils(self):
        """
        集合操作
        应用排行榜
        :return:
        """
        zset_name = "zset_name"
        zset_value = {
            "zset_1": 23,
            "zset_2": 23.56,
            "zset_3": 23,
            "zset_4": -4,
            "zset_5": 0
        }
        result = self._client.zadd(zset_name, **zset_value)
        print("zset ZADD key:", zset_name, " result:", result)
        result = self._client.zcard(zset_name)
        print("zset ZCARD key:", zset_name, " result:", result)
        zset_score_value = "zset_4"
        result = self._client.zscore(zset_name, zset_score_value)
        print("zset ZSCORE key:", zset_name, "value:", zset_score_value,
              " result:", result)
        result = self._client.zrank(zset_name, zset_score_value)
        print("zset ZRANK key:", zset_name, "value:", zset_score_value,
              " result:", result)
        result = self._client.zrevrank(zset_name, zset_score_value)
        print("zset ZREVRANK key:", zset_name, "value:", zset_score_value,
              " result:", result)
        zset_cursor = 0
        index, result = self._client.zscan(zset_name, zset_cursor)
        print("zset ZSCAN key:", zset_name, " result:", result, "type:",
              type(result))

        zset_min = 0  # Start From 0
        zset_max = 2
        zset_num = 2
        result = self._client.zrange(zset_name, zset_min, zset_max)
        print("zset ZRANGE key:", zset_name, "min:", zset_min, " max:",
              zset_max, " result:", result)
        # self._client.zrangebylex(zset_name, 0, 2, num=2)
        # self._client.zrangebyscore(zset_name, 0, 2, num=2)
        self._client.delete(zset_name)

    def hash_utils(self):
        hash_name = "hash_name"
        hash_key = "hask_key"
        hash_value = "hash_value"
        result = self._client.hset(hash_name, hash_key, hash_value)
        print("hash HSET key:", hash_name, " field:", hash_key, " value:",
              hash_value, " result:", result)
        hash_content = {"name": "lee", "age": 34, "birth": 2009}
        result = self._client.hmset(hash_name, hash_content)
        print("hash HMSET content:", hash_content, " result:", result)
        result = self._client.hlen(hash_name)
        print("hash HLEN key:", hash_name, " result:", result)
        result = self._client.hexists(hash_name, hash_key)
        print("hash HEXISTS key:", hash_name, " field:", hash_key, " result:",
              result)
        result = self._client.hget(hash_name, hash_key)
        print("hash HGET key:", hash_name, " field:", hash_key, " result:",
              result)
        hash_keys = ("name", "age")
        result = self._client.hmget(hash_name, *hash_keys)
        print("hash HMGET key:", hash_name, " field:", hash_keys, " result:",
              result)
        hash_cursor = 0
        result = self._client.hscan(hash_name, hash_cursor)
        print("hash HSCAN key:", hash_name, " result:", result)
        result = self._client.hkeys(hash_name)
        print("hash HKEYS key:", hash_name, "result:", result)
        result = self._client.hdel(hash_name, hash_key)
        print("hash HDEL key:", hash_name, " field:", hash_key, " result:",
              result)
        result = self._client.hdel(hash_name, *hash_keys)
        print("hash HDEL key:", hash_name, " field:", hash_key, " result:",
              result)
Beispiel #39
0
class LibRedis:

    # 默认所有key的前缀
    key_prefix = 'RAWE_'

    # redis 连接对象
    obj_redis = None

    # 默认的过期时间为3天
    DEFAULT_EXPIRE = 259200

    def __init__(self, host='127.0.0.1', port=6379, db=0, prefix=None, charset='utf-8'):
        """
        初始化
        """
        if not host or not port:
            return None

        if prefix:
            self.key_prefix = prefix.strip()
        # construct
        self.obj_redis = StrictRedis(
            host=host, port=port, db=db, charset='utf-8')

    def key_make(self, keyname=None):
        """
        处理所有key,增加前缀
        如果实例化时没有设置,则使用默认前缀
        """
        if not keyname:
            return None

        return self.key_prefix + str(keyname).strip()

    def set_expire(self, keyname=None):
        """
        设置key的过期时间,装饰器调用
        """
        if not keyname:
            return None

        return self.obj_redis.expire(self.key_make(keyname), self.DEFAULT_EXPIRE)

    # --------------------------------------------------------
    # String
    # --------------------------------------------------------

    @wraps_set_expire
    def set(self, keyname=None, value=None):
        """
        设置指定 key 的值。
        如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。
        return:
        设置操作成功完成时,才返回 OK
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        if isinstance(value, str):
            value = value.strip()

        return self.obj_redis.set(keyname, value)

    def get(self, keyname=None):
        """
        获取指定 key 的值。
        return:
        key 的值
        如果 key 不存在,返回 nil。
        如果key 储存的值不是字符串类型,返回一个错误。
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.get(keyname)

        return None if not result else bytes.decode(result)

    def delete(self, keyname=None):
        """
        删除已存在的键。不存在的 key 会被忽略
        return:
        被删除 key 的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.delete(keyname)

    @wraps_set_expire
    def append(self, keyname=None, value=None):
        """
        为指定的 keyname 追加值
        如果 keyname 已经存在并且是一个字符串,
        APPEND 命令将 value 追加到 keyname 原来的值的末尾。
        如果 keyname 不存在,
        APPEND 就简单地将给定 keyname 设为 value ,就像执行 SET keyname value 一样
        return:
        追加指定值之后, keyname 中字符串的长度
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        if isinstance(value, str):
            value = value.strip()
        else:
            value = str(value)

        return self.obj_redis.append(keyname, value)

    @wraps_set_expire
    def incr(self, keyname=None, expire=None):
        """
        将 keyname 中储存的数字值增一。
        如果 keyname 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内。
        return:
        执行 INCR 命令之后 key 的值
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.incr(keyname, 1)

    @wraps_set_expire
    def incrBy(self, keyname=None, amount=1):
        """
        将 keyname 中储存的数字加上指定的增量值。
        如果 keyname 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内。
        return:
        加上指定的增量值之后, key 的值
        """
        if not keyname or not amount:
            return None

        keyname = self.key_make(keyname.strip())

        if isinstance(amount, int):
            amount = max(0, amount)
        else:
            amount = 1

        return self.obj_redis.incrby(keyname, amount)

    @wraps_set_expire
    def decr(self, keyname=None):
        """
        将 key 中储存的数字值减一。
        如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内。
        return:
        执行命令之后 key 的值
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.decr(keyname, 1)

    @wraps_set_expire
    def decrBy(self, keyname=None, amount=1):
        """
        将 keyname 所储存的值减去指定的减量值。
        如果 keyname 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内
        """
        if not keyname or not amount:
            return None

        keyname = self.key_make(keyname.strip())
        amount = int(amount)
        return self.obj_redis.decr(keyname, amount)

    # --------------------------------------------------------
    # Hash 哈希
    # 一个string类型的field和value的映射表,hash特别适合用于存储对象
    # 每个 hash 可以存储 232 - 1 键值对(40多亿)
    # --------------------------------------------------------

    @wraps_set_expire
    def hSet(self, keyname=None, key=None, value=None):
        """
        从哈希名为keyname中添加key1->value1 将哈希表key中的域field的值设为value。-ok -ok
        如果key不存在,一个新的哈希表被创建并进行hset操作。
        如果域field已经存在于哈希表中,旧值将被覆盖。
        错误则 返回 FALSE
        如果字段是哈希表中的一个新建字段,并且值设置成功,返回 1 。 
        如果哈希表中域字段已经存在且旧值已被新值覆盖,返回 0 。
        """
        if not keyname or not key or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        key = key.strip()
        return self.obj_redis.hset(keyname, key, value)

    @wraps_set_expire
    def hGet(self, keyname=None, key=None):
        """
        获取存储在哈希表中指定字段的值
        返回给定字段的值。如果给定的字段或 key 不存在时,返回 None 
        """
        if not keyname or not key:
            return None

        keyname = self.key_make(keyname.strip())
        key = key.strip()

        result = self.obj_redis.hget(keyname, key)
        if not result:
            return None

        # bytes to str
        return bytes.decode(result)

    @wraps_set_expire
    def hLen(self, keyname=None):
        """
        获取哈希表中字段的数量
        哈希表中字段的数量。 当 keyname 不存在时,返回 0 
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.hlen(keyname)

    @wraps_set_expire
    def hKeys(self, keyname=None):
        """
        获取哈希表中的所有域(field)
        包含哈希表中所有域(field)列表。 
        当 key 不存在时,返回一个空列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.hkeys(keyname)
        if not result:
            return None

        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    @wraps_set_expire
    def hVals(self, keyname=None):
        """
        哈希表所有域(field)的值
        包含哈希表中所有域(field)值的列表。 
        当 key 不存在时,返回一个空表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.hvals(keyname)
        if not result:
            return None

        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    @wraps_set_expire
    def hGetAll(self, keyname=None):
        """
        获取在哈希表中指定 keyname 的所有字段和值
        返回哈希表中,所有的字段和值
        在返回值里,紧跟每个字段名(field name)之后是字段的值(value),
        所以返回值的长度是哈希表大小的两倍。
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.hgetall(keyname)
        if not result:
            return None

        # bytes to str
        ret_dict = dict()
        for k, v in result.items():
            ret_dict[bytes.decode(k)] = bytes.decode(v)

        return ret_dict

    def hExists(self, keyname=None, key=None):
        """
        查看哈希表 keyname 中,是否存在键名为key的字段
        ashname含有给定字段key,返回 True。 
        keyname不存在 或 key 不存在,返回 False
        """
        if not keyname or key is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.hexists(keyname, key)

    def hDel(self, keyname=None, *keys):
        """
        删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略
        返回值
        被成功删除字段的数量,不包括被忽略的字段
        keyname 或 key 不存在则返回 0
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.hdel(keyname, *keys)

    # --------------------------------------------------------
    # List 列表, 左(Left)为头部,右(Right)为尾部
    # 一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)
    # --------------------------------------------------------

    @wraps_set_expire
    def lPush(self, keyname=None, *values):
        """
        将一个或多个值插入到列表头部, 返回操作后列表的长度。
        如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 
        当 key 存在但不是列表类型时,返回一个错误。
        注意:在Redis 2.4版本以前的 LPUSH 命令,都只接受单个 value 值
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.lpush(keyname, *values)

    @wraps_set_expire
    def lPop(self, keyname=None):
        """
        弹出队列头部元素,移除并返回列表的第一个元素。
        返回列表的第一个元素。 当列表 key 不存在时,返回 None 
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.lpop(keyname)

    @wraps_set_expire
    def rPush(self, keyname=None, *values):
        """
        将一个或多个值插入到列表的尾部(最右边), 返回操作后列表的长度。
        如果列表不存在,一个空列表会被创建并执行 RPUSH 操作。 
        当列表存在但不是列表类型时,返回一个错误。
        注意:在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值。

        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.rpush(keyname, *values)

    @wraps_set_expire
    def rPop(self, keyname=None):
        """
        移除并获取列表最后一个元素
        返回列表的最后一个元素。 当列表不存在时,返回 None
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.rpop(keyname)
        if not result:
            return None
        # bytes to str
        return bytes.decode(result)

    @wraps_set_expire
    def lLen(self, keyname=None):
        """
        获取列表长度 
        如果列表 key 不存在,则 key 被解释为一个空列表,返回 0  
        如果 key 不是列表类型,返回一个错误
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.llen(keyname)

    @wraps_set_expire
    def lTrim(self, keyname=None, start=0, end=-1):
        """
        让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
        下标 0 表示列表的第一个元素,1 表示列表的第二个元素
        -1 表示列表的最后一个元素,-2 表示列表的倒数第二个元素
        返回 True
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.ltrim(keyname, start, end)

    @wraps_set_expire
    def lGetRange(self, keyname=None, start=0, end=-1):
        """
        返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定
        下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素
        -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素
        返回一个列表,包含指定区间内的元素
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.lrange(keyname, start, end)
        if not result:
            return None
        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    @wraps_set_expire
    def lRemove(self, keyname=None, value=None, count=1):
        """
        根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。
        COUNT 的值可以是以下几种:
        count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
        count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
        count = 0 : 移除表中所有与 VALUE 相等的值。
        返回被移除元素的数量。 列表或元素不存在时返回 0
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.lrem(keyname, count, value)

    # --------------------------------------------------------
    # Set 无序集合
    # Set 是 String 类型的无序集合。集合成员是唯一的。
    # 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
    # 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)
    # --------------------------------------------------------

    @wraps_set_expire
    def sAdd(self, keyname=None, *values):
        """
        将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。
        假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。
        当集合 key 不是集合类型时,返回一个错误。
        注意:在Redis2.4版本以前, SADD 只接受单个成员值。
        """
        if not keyname:
            return None
        keyname = self.key_make(keyname.strip())
        return self.obj_redis.sadd(keyname, *values)

    @wraps_set_expire
    def sCard(self, keyname=None):
        """
        获取集合key中元素的数量
        集合的数量。 当集合 key 不存在时,返回 0
        """
        if not keyname:
            return None
        keyname = self.key_make(keyname.strip())
        return self.obj_redis.scard(keyname)

    def sDiff(self, keyname=None, *keys):
        """
        差集
        返回所给key列表想减后的集合,相当于求差集
        不存在的集合 key 将视为空集。
        请注意顺序是前面的集合,减去后面的集合,求差集
        返回包含差集成员的列表
        """
        if not keyname:
            return None

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        result = self.obj_redis.sdiff(keyname, *other_keys)
        if not result:
            return None

        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sDiffStore(self, store_key=None, key=None, *keys):
        """
        差集并存储
        给定所有集合的差集并存储在 store_key 中
        将给定集合之间的差集存储在指定的集合中。
        如果指定的集合 key 已存在,则会被覆盖
        返回store_key结果集中的元素数量
        """
        if not store_key or not key:
            return None

        store_key = self.key_make(store_key.strip())
        key = self.key_make(key.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        return self.obj_redis.sdiffstore(store_key, key, *other_keys)

    def sInter(self, keyname=None, *keys):
        """
        交集
        返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 
        当给定集合当中有一个空集或key不存在时,结果也为空集(根据集合运算定律)。
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        result = self.obj_redis.sinter(keyname, *other_keys)
        if not result:
            return None

        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sInterStore(self, store_key=None, key=None, *keys):
        """
        交集并存储
        将给定集合之间的交集存储在指定的集合store_key中。
        如果指定的集合已经存在,则将其覆盖
        返回store_key存储交集的集合的元素数量
        """
        if not store_key or not key:
            return None

        store_key = self.key_make(store_key.strip())
        key = self.key_make(key.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        return self.obj_redis.sinterstore(store_key, key, *other_keys)

    def sUnion(self, keyname=None, *keys):
        """
        并集
        所给key列表所有的值,相当于求并集
        给定集合的并集。不存在的集合 key 被视为空集。
        返回并集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        result = self.obj_redis.sunion(keyname, *other_keys)
        if not result:
            return None

        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sUnionStore(self, store_key=None, key=None, *keys):
        """
        并集存储
        将给定集合的并集存储在指定的集合 store_key 中。
        如果 store_key 已经存在,则将其覆盖
        返回store_key存储并集的集合的元素数量
        """
        if not store_key or not key:
            return None

        store_key = self.key_make(store_key.strip())
        key = self.key_make(key.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        return self.obj_redis.sunionstore(store_key, key, *other_keys)

    @wraps_set_expire
    def sIsMember(self, keyname=None, value=None):
        """
        判断成员元素是否是集合的成员
        如果成员元素是集合的成员,返回 True 
        如果成员元素不是集合的成员,或 key 不存在,返回 False
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.sismember(keyname, value)

    @wraps_set_expire
    def sMembers(self, keyname=None):
        """
        返回集合中的所有的成员。 
        不存在的集合 key 被视为空集合
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.smembers(keyname)

        if not result:
            return None
        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sRem(self, keyname=None, *values):
        """
        删除该数组中对应的值
        移除集合中的一个或多个成员元素,不存在的成员元素会被忽略。
        当 key 不是集合类型,返回一个错误。
        在 Redis 2.4 版本以前, SREM 只接受单个成员值。
        返回被成功移除的元素的数量,不包括被忽略的元素
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.srem(keyname, *values)

    @wraps_set_expire
    def sPop(self, keyname=None):
        """
        移除并返回集合中的一个随机元素
        将随机元素从集合中移除并返回
        移除的随机元素。 当集合不存在或是空集时,返回 None
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.spop(keyname)

        # bytes to str
        return None if not result else bytes.decode(result)

    @wraps_set_expire
    def sRandMember(self, keyname=None, count=1):
        """
        返回集合中的随机元素,而不对集合进行任何改动
        从 Redis 2.6 版本开始, Srandmember 命令接受可选的 count 参数:
        如果 count 为正数,且小于集合基数,
            返回一个包含 count 个元素的数组,数组中的元素各不相同。
        如果 count 大于等于集合基数,那么返回整个集合。
        如果 count 为负数,返回一个数组,
            数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
        返回:随机个数的元素列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())

        if isinstance(count, int):
            count = max(0, count)
        else:
            count = 1

        result = self.obj_redis.srandmember(keyname, count)

        if not result:
            return None

        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    # --------------------------------------------------------
    # Zset( sorted set ) 有序集合
    # 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员
    # 有序集合的成员是唯一的,但分数(score)却可以重复
    # 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)
    # 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)
    # --------------------------------------------------------

    @wraps_set_expire
    def zAdd(self, keyname=None, **kwargs):
        """
        将一个或多个成员元素及其分数值加入到有序集当中。
        如果某个成员已经是有序集的成员,那么更新这个成员的分数值,
        并通过重新插入这个成员元素,来保证该成员在正确的位置上。
        如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
        当 key 存在但不是有序集类型时,返回一个错误。
        返回:
            被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
        注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素
        **kwargs: name1=score1, name2=score2
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zadd(keyname, **kwargs)

    def zRangeByScore(self, keyname=None, min=None, max=None, withscores=False):
        """
        分数值正序
        返回有序集中指定分数区间内的所有的成员。
        有序集成员按分数值递减(从大到小)的次序排列。
        具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列
        返回;
        指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrangebyscore(
            keyname, min, max, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRevRangeByScore(self, keyname=None, max=None, min=None, withscores=False):
        """
        分数值逆序
        返回有序集中指定分数区间内的所有的成员。
        有序集成员按分数值递减(从大到小)的次序排列。
        具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列。
        返回;
        指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrevrangebyscore(
            keyname, max, min, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRank(self, keyname=None, member=None):
        """
        排名正序
        返回有序集中指定成员的排名。
        其中有序集成员按分数值递增(从小到大)顺序排列
        如果成员是有序集 key 的成员,返回 member 的排名。
        如果成员不是有序集 key 的成员,返回 None 。
        """
        if not keyname or member is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zrank(keyname, member)

    def zRevRank(self, keyname=None, member=None):
        """
        排名逆序
        返回有序集中指定成员的排名。
        其中有序集成员按分数值递减(从大到小)排序
        如果成员是有序集 key 的成员,返回 member 的排名。
        如果成员不是有序集 key 的成员,返回 None 。
        """
        if not keyname or member is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zrevrank(keyname, member)

    def zRange(self, keyname=None, start=None, end=None, withscores=False):
        """
        位置正序
        返回有序集中,指定区间内的成员。
        其中成员的位置按分数值递增(从小到大)来排序。
        具有相同分数值的成员按字典序(lexicographical order )来排列
        返回指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrange(
            keyname, start, end, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRevrange(self, keyname=None, start=None, end=None, withscores=False):
        """
        位置逆序
        返回有序集中,指定区间内的成员。
        其中成员的位置按分数值递减(从大到小)来排列。
        具有相同分数值的成员按字典序的逆序(reverse lexicographical order)排列
        返回指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrevrange(
            keyname, start, end, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRem(self, keyname, *member):
        """
        移除有序集中的一个或多个成员,不存在的成员将被忽略。
        当 key 存在但不是有序集类型时,返回一个错误。
        注意: 在 Redis 2.4 版本以前, ZREM 每次只能删除一个元素。
        返回被成功移除的成员的数量,不包括被忽略的成员0
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zrem(keyname, *member)

    def zRemRangeByRank(self, keyname=None, min=None, max=None):
        """
        删除正序
        移除有序集中,指定排名(rank)区间内的所有成员
        返回被移除成员的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zremrangebyrank(keyname, min, max)

    def zRemrangebyscore(self, keyname=None, min=None, max=None):
        """
        删除正序
        移除有序集中,指定分数(score)区间内的所有成员
        返回被移除成员的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zremrangebyscore(keyname, min, max)

    def zCard(self, keyname=None):
        """
        计算集合中元素的数量
        当 key 存在且是有序集类型时,返回有序集的基数。
        当 key 不存在时,返回 0
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zcard(keyname)

    def zCount(self, keyname=None, min=None, max=None):
        """
        计算有序集合中指定分数区间的成员数量
        返回分数值在 min 和 max 之间的成员的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zcount(keyname, min, max)
# key - 添加的key
# value - 添加的key对应的值
# 给userinfo 添加了一个username,值为articuly
redis.hset('userinfo', 'username', 'articuly')
redis.hset('userinfo', 'age', 30)
redis.hset('userinfo', 'sex', 1)
# 获取字典 - hgetall(name)
# 返回name的全部项
userinfo = redis.hgetall('userinfo')
# 获取字典中的某一项 - hget(name, key)
# 返回name中的key项,不存在返回None
redis.hget('userinfo', 'age')
redis.hget('userinfo', 'name')
# 获得字典的长度 - hlen(name)
redis.hlen('userinfo')
# 获得所有的key - hkeys(name)
redis.hkeys('userinfo')
# 获得所有的value - hvals(name)
redis.hvals('userinfo')
# 获取name的多个key值 - hmget(name, "key1", "key2")
redis.hmget('userinfo', 'username', 'age')
# 加减操作
# hincrby(name, key, amount=1)
redis.hincrby('userinfo', 'age', 10)
redis.hincrby('userinfo', 'age', 5)
# 删除key - hdel(name, key1,key2)
# 返回删除的项数
redis.hkeys('userinfo')
redis.hdel('userinfo', 'age')
redis.hkeys('userinfo')