1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
|