/usr/share/pyshared/translate/misc/lru.py is in translate-toolkit 1.10.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 120 121 122 123 124 125 126 127 128 129 130 131 132 | #!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2009 Zuza Software Foundation
#
# This file is part of translate.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
from collections import deque
from weakref import WeakValueDictionary
import gc
class LRUCachingDict(WeakValueDictionary):
"""Caching dictionary like object that discards the least recently
used objects when number of cached items exceeds maxsize.
cullsize is the fraction of items that will be discarded when
maxsize is reached.
"""
def __init__(self, maxsize, cullsize=2, peakmult=10, aggressive_gc=True,
*args, **kwargs):
self.cullsize = max(2, cullsize)
self.maxsize = max(cullsize, maxsize)
self.aggressive_gc = aggressive_gc
self.peakmult = peakmult
self.queue = deque()
WeakValueDictionary.__init__(self, *args, **kwargs)
def cull(self):
"""free memory by deleting old items from cache"""
# maximum cache size exceeded, cull old items
#
# note queue is the real cache but its size is boundless
# since it might have duplicate references.
#
# don't bother culling if queue is smaller than weakref,
# this means there are too many references outside the
# cache, culling won't free much memory (if any).
while len(self) >= self.maxsize <= len(self.queue):
cullsize = max(int(len(self.queue) / self.cullsize), 2)
try:
for i in xrange(cullsize):
self.queue.popleft()
except IndexError:
# queue is empty, bail out.
#FIXME: should we force garbage collection here too?
break
# call garbage collecter manually since objects
# with circular references take some time to get
# collected
if self.aggressive_gc:
rounds = min(max(int(self.aggressive_gc), 5), 50)
for i in xrange(rounds):
gc.collect()
else:
gc.collect()
def __setitem__(self, key, value):
# check boundaries to minimize duplicate references
while len(self.queue) and self.queue[0][0] == key:
# item at left end of queue pop it since it'll be appended
# to right
self.queue.popleft()
while len(self.queue) and self.queue[-1][0] == key:
# item at right end of queue pop it since it'll be
# appended again
self.queue.pop()
if (len(self) >= self.maxsize or
len(self.queue) >= self.maxsize * self.peakmult):
self.cull()
self.queue.append((key, value))
WeakValueDictionary.__setitem__(self, key, value)
def __getitem__(self, key):
value = WeakValueDictionary.__getitem__(self, key)
# check boundaries to minimiza duplicate references
while len(self.queue) > 0 and self.queue[0][0] == key:
# item at left end of queue pop it since it'll be appended
# to right
self.queue.popleft()
# only append if item is not at right end of queue
if not (len(self.queue) and self.queue[-1][0] == key):
if (len(self) >= self.maxsize or
len(self.queue) >= self.maxsize * self.peakmult):
self.cull()
self.queue.append((key, value))
return value
def __delitem__(self, key):
# can't efficiently find item in queue to delete, check
# boundaries. otherwise just wait till next cache purge
while len(self.queue) and self.queue[0][0] == key:
# item at left end of queue pop it since it'll be appended
# to right
self.queue.popleft()
while len(self.queue) and self.queue[-1][0] == key:
# item at right end of queue pop it since it'll be
# appended again
self.queue.pop()
return WeakValueDictionary.__delitem__(self, key)
def clear(self):
self.queue.clear()
return WeakValueDictionary.clear(self)
def setdefault(self, key, default):
if key not in self:
self[key] = default
return self[key]
|