1
0

kstore.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # The contents of this file are subject to the BitTorrent Open Source License
  2. # Version 1.1 (the License). You may not copy or use this file, in either
  3. # source code or executable form, except in compliance with the License. You
  4. # may obtain a copy of the License at http://www.bittorrent.com/license/.
  5. #
  6. # Software distributed under the License is distributed on an AS IS basis,
  7. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  8. # for the specific language governing rights and limitations under the
  9. # License.
  10. try:
  11. from random import sample
  12. except ImportError:
  13. from random import choice
  14. def sample(l, n):
  15. if len(l) <= n:
  16. return l
  17. d = {}
  18. while len(d) < n:
  19. d[choice(l)] = 1
  20. return d.keys()
  21. from BTL.platform import bttime as time
  22. class KItem:
  23. def __init__(self, key, value):
  24. self.t = time()
  25. self.k = key
  26. self.v = value
  27. def __cmp__(self, a):
  28. # same value = same item, only used to keep dupes out of db
  29. if self.v == a.v:
  30. return 0
  31. # compare by time
  32. if self.t < a.t:
  33. return -1
  34. elif self.t > a.t:
  35. return 1
  36. else:
  37. return 0
  38. def __hash__(self):
  39. return self.v.__hash__()
  40. def __repr__(self):
  41. return `(self.k, self.v, time() - self.t)`
  42. ## in memory data store for distributed tracker
  43. ## keeps a list of values per key in dictionary
  44. ## keeps expiration for each key in a queue
  45. ## can efficiently expire all values older than a given time
  46. ## can insert one val at a time, or a list: ks['key'] = 'value' or ks['key'] = ['v1', 'v2', 'v3']
  47. class KStore:
  48. def __init__(self):
  49. self.d = {}
  50. self.q = []
  51. def __getitem__(self, key):
  52. return [x.v for x in self.d[key]]
  53. def __setitem__(self, key, value):
  54. if type(value) == type([]):
  55. [self.__setitem__(key, v) for v in value]
  56. return
  57. x = KItem(key, value)
  58. try:
  59. l = self.d[key]
  60. except KeyError:
  61. self.d[key] = [x]
  62. else:
  63. # this is slow
  64. try:
  65. i = l.index(x)
  66. del(l[i])
  67. except ValueError:
  68. pass
  69. l.insert(0, x)
  70. self.q.append(x)
  71. def __delitem__(self, key):
  72. del(self.d[key])
  73. def __len__(self):
  74. return len(self.d)
  75. def keys(self):
  76. return self.d.keys()
  77. def values(self):
  78. return [self[key] for key in self.keys()]
  79. def items(self):
  80. return [(key, self[key]) for key in self.keys()]
  81. def expire(self, t):
  82. #.expire values inserted prior to t
  83. try:
  84. while self.q[0].t <= t:
  85. x = self.q.pop(0)
  86. try:
  87. l = self.d[x.k]
  88. try:
  89. while l[-1].t <= t:
  90. l.pop()
  91. except IndexError:
  92. del(self.d[x.k])
  93. except KeyError:
  94. pass
  95. except IndexError:
  96. pass
  97. def sample(self, key, n):
  98. # returns n random values of key, or all values if less than n
  99. try:
  100. l = [x.v for x in sample(self.d[key], n)]
  101. except ValueError:
  102. l = [x.v for x in self.d[key]]
  103. return l