def test_lock(self, field_name, must_exists=True): """ Test that a lock exists or not on the given field name. """ lock_key = make_key(self.model._name, 'lock-for-update', field_name) method = self.test.assertTrue if must_exists else self.test.assertFalse method(LimpydBaseTest.database.connection.exists(lock_key))
def _unique_key(self, prefix=None): """ Create a unique key. """ prefix_parts = [self.model._name, '__collection__'] if prefix: prefix_parts.append(prefix) return unique_key(self.connection, prefix=make_key(*prefix_parts))
def _zset_to_keys(self, key, values=None, alpha=False): """ Convert a redis sorted set to a list of keys, to be used by sort. Each key is on the following format, for each value in the sorted set: ramdom_string:value-in-the-sorted-set => score-of-the-value The random string is the same for all keys. If values is not None, only these values from the sorted set are saved as keys. If a value in values is not on the sorted set, it's still saved as a key but with a default value ('' is alpha is True, else '-inf') """ conn = self.connection default = '' if alpha else '-inf' if values is None: # no values given, we get scores from the whole sorted set result = conn.zrange(key, start=0, end=-1, withscores=True) values = list(islice(chain.from_iterable(result), 0, None, 2)) else: # we have values, we'll get only their scores if isinstance(self.model.database, PipelineDatabase): # if available, use the pipeline of our database to get all # scores in one redis call with self.model.database.pipeline(transaction=False) as pipe: for value in values: pipe.zscore(key, value) scores = pipe.execute() else: # no pipeline, we have to do a call for each value scores = [] for value in values: scores.append(conn.zscore(key, value)) # combine values and scores in one list result = [] for index, value in enumerate(values): score = scores[index] if score is None: score = default result.append((value, score)) # create a temporary key for each (value,score) tuple base_tmp_key = self._unique_key('tmp') conn.set(base_tmp_key, 'working...') # only to "reserve" the main tmp key tmp_keys = set() # use a mapping dict (tmp_key_with_value=>score) to use in mset mapping = {} for value, score in result: tmp_key = make_key(base_tmp_key, value) tmp_keys.add(tmp_key) mapping[tmp_key] = score # set all keys in one call conn.mset(mapping) return base_tmp_key, tmp_keys
def __init__(self, field, timeout=5, sleep=0.1): """ Save the field and create a real lock,, using the correct connection and a computed lock key based on the names of the field and its model. """ self.field = field self.sub_lock_mode = False super(FieldLock, self).__init__( redis=field._model.get_connection(), name=make_key(field._model._name, 'lock-for-update', field.name), timeout=timeout, sleep=sleep, )
def test_integer_element(self): self.assertEqual("integer:key:1", make_key("integer", "key", 1))
def test_unicode_element(self): self.assertEqual(u"french:key:clé", make_key("french", "key", u"clé"))
def test_multi_element_key(self): self.assertEqual("complex:key", make_key("complex", "key"))
def test_simple_key(self): self.assertEqual("simple_key", make_key("simple_key"))
def make_key(self, *args): """ Simple shortcut to the make_key global function to create a redis key based on all given arguments. """ return make_key(*args)
def make_key(cls, *args): return make_key(*args)
def make_key(self, *args): return make_key(*args)