diff options
Diffstat (limited to 'khashmir/kstore.py')
-rw-r--r-- | khashmir/kstore.py | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/khashmir/kstore.py b/khashmir/kstore.py new file mode 100644 index 0000000..5c01200 --- /dev/null +++ b/khashmir/kstore.py @@ -0,0 +1,119 @@ +# The contents of this file are subject to the BitTorrent Open Source License +# Version 1.1 (the License). You may not copy or use this file, in either +# source code or executable form, except in compliance with the License. You +# may obtain a copy of the License at http://www.bittorrent.com/license/. +# +# Software distributed under the License is distributed on an AS IS basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. + +try: + from random import sample +except ImportError: + from random import choice + def sample(l, n): + if len(l) <= n: + return l + d = {} + while len(d) < n: + d[choice(l)] = 1 + return d.keys() + +from BitTorrent.platform import bttime as time + +class KItem: + def __init__(self, key, value): + self.t = time() + self.k = key + self.v = value + def __cmp__(self, a): + # same value = same item, only used to keep dupes out of db + if self.v == a.v: + return 0 + + # compare by time + if self.t < a.t: + return -1 + elif self.t > a.t: + return 1 + else: + return 0 + + def __hash__(self): + return self.v.__hash__() + + def __repr__(self): + return `(self.k, self.v, time() - self.t)` + +## in memory data store for distributed tracker +## keeps a list of values per key in dictionary +## keeps expiration for each key in a queue +## can efficiently expire all values older than a given time +## can insert one val at a time, or a list: ks['key'] = 'value' or ks['key'] = ['v1', 'v2', 'v3'] +class KStore: + def __init__(self): + self.d = {} + self.q = [] + + def __getitem__(self, key): + return [x.v for x in self.d[key]] + + def __setitem__(self, key, value): + if type(value) == type([]): + [self.__setitem__(key, v) for v in value] + return + x = KItem(key, value) + try: + l = self.d[key] + except KeyError: + self.d[key] = [x] + else: + # this is slow + try: + i = l.index(x) + del(l[i]) + except ValueError: + pass + l.insert(0, x) + self.q.append(x) + + def __delitem__(self, key): + del(self.d[key]) + + def __len__(self): + return len(self.d) + + def keys(self): + return self.d.keys() + + def values(self): + return [self[key] for key in self.keys()] + + def items(self): + return [(key, self[key]) for key in self.keys()] + + def expire(self, t): + #.expire values inserted prior to t + try: + while self.q[0].t <= t: + x = self.q.pop(0) + try: + l = self.d[x.k] + try: + while l[-1].t <= t: + l.pop() + except IndexError: + del(self.d[x.k]) + except KeyError: + pass + except IndexError: + pass + + def sample(self, key, n): + # returns n random values of key, or all values if less than n + try: + l = [x.v for x in sample(self.d[key], n)] + except ValueError: + l = [x.v for x in self.d[key]] + return l |