This file is indexed.

/usr/share/pyshared/mx/Misc/Cache.py is in python-egenix-mxtools 3.2.1-1ubuntu1.

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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
""" Cache - Generic cache implementation

    Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
    See the documentation for further information on copyrights,
    or contact the author. All Rights Reserved.
"""
import sys
from mx import Tools

# Weight table
MAXLOCALITY = 256
_weights = [1] * MAXLOCALITY

# maximal history size (must somewhat larger than MAXLOCALITY)
HISTORYLIMIT = 2 * MAXLOCALITY

# Cut goal that has to be reached (self.max_cachesize * float(DENOM / NOM))
DENOM = 3
NOM = 4

# Print debugging info ?
_debug = 0

# Init globals
class _modinit:
    import math
    l = Tools.frange(0,1,MAXLOCALITY)
    for i,factor in Tools.irange(l):
        _weights[i] = int((math.exp(factor) - 1.0) * 8192)
        if _debug:
            print i,'. weight =',_weights[i]
del _modinit

### Classes

class NotCached:

    """ A singleton that can be used in conjunction with the .get()
        method of Cache. It behaves like None.
    """
    def __nonzero__(self):
        return 0
    __len__ = __nonzero__

NotCached = NotCached()

###

class Cache:

    """ Tunable cache implementation

        The following parameters influence the cache behaviour:
        - max_cachesize:        the cache will be cut smaller when this limit
                                is reached
        - max_elementsize:      elements with size greate than this limit
                                will not be cached
        - locality:             these many elements will be looked at in
                                the hit statistics to determine how important
                                a specific entry is
    """
    data = None                 # Dict. of id:value cache entries
    put_history = None          # Reverse list of id puts; last is most
                                # recent access; contains id for each access
    get_history = None          # Reverse list of id gets; last is most
                                # recent access; contains id for each access

    def __init__(self,max_cachesize=200,
                      max_elementsize=4096,
                      locality=50):

        self.max_cachesize = max_cachesize
        self.max_elementsize = max_elementsize
        if locality > MAXLOCALITY:
            raise ValueError,'locality must be <= %i' % MAXLOCALITY
        self.locality = locality

        self.cachesize = 0
        self.cuts = 0
        self.misses = 0
        self.hits = 0

        self.data = {}
        self.put_history = []
        self.get_history = []

    def cut(self,

            NOM=NOM,DENOM=DENOM):

        """ Force a cut of the cache's contents.

            This will make room for at least one new entry.
        """
        if _debug:
            print '  Cutting down cache size...'
        cachesize = self.cachesize
            
        # Cut the cache down to the entries in recent get history
        newdata = {}
        known_key = newdata.has_key
        data = self.data
        for id in self.get_history[-self.locality:]:
            if known_key(id):
                continue
            try:
                newdata[id] = data[id]
            except KeyError:
                pass

        cachesize = len(newdata)
        if _debug:
            print '   Size after cut to recent history:',cachesize

        # Check
        if cachesize * NOM >= self.max_cachesize * DENOM:

            # Calculate weights
            d = {}
            weights = _weights
            d_get = d.get
            for i,id in Tools.irange(self.get_history[-self.locality:]):
                if not known_key(id):
                    continue
                d[id] = d_get(id,0) + weights[i]

            # Delete all entries left from median
            ranking = Tools.sortedby(d.items(),1)
            if _debug:
                print '   Ranking:',ranking
            for id,weight in ranking[:len(d)/2]:
                if _debug:
                    print '   Deleting',id,'with weight =',weight
                del newdata[id]

            # Check
            cachesize = len(newdata)

            if cachesize * NOM >= self.max_cachesize * DENOM:
                # Ok, so the smart way didn't work...
                if _debug:
                    print '   Did not work, going the hard way...'
                newdata.clear()
                cachesize = 0

        self.data = newdata
        self.cachesize = cachesize
        self.cuts = self.cuts + 1

    def clear(self):

        """ Clear the cache.
        """
        self.cachesize = 0
        self.data = {}
        self.history = []

    def get(self,id,default=NotCached,

            HISTORYLIMIT=HISTORYLIMIT):

        """ Get a value from the cache or return default if it is
            not cached.
        """
        item = self.data.get(id,None)
        if item is None:
            self.misses = self.misses + 1
            return default

        # Add "hit"
        self.get_history.append(id)
        if len(self.get_history) > HISTORYLIMIT:
            del self.get_history[-self.locality:]
        self.hits = self.hits + 1

        return item

    def put(self,id,value,sizeof=Tools.sizeof,

            HISTORYLIMIT=HISTORYLIMIT):

        """ Add a value to the cache or update an existing one.
        """
        size = sizeof(value)
        if size > self.max_elementsize:
            return

        # Adding a new entry: make sure there is room
        if not self.data.has_key(id):
            if _debug:
                print '  Adding',id
            self.cachesize = cachesize = self.cachesize + 1
            if cachesize > self.max_cachesize:
                self.cut()

        self.data[id] = value
        self.put_history.append(id)
        if len(self.put_history) > HISTORYLIMIT:
            del self.put_history[-self.locality:]


    # Aliases
    add = put
    update = put

    def delete(self,id):

        """ Delete an entry from the cache.

            It is not an error, if the entry is not currently in the cache.
        """
        try:
            del self.data[id]
        except KeyError:
            pass

    # Aliases
    remove = delete

###

if __name__ == '__main__':
    c = Cache(10,100,locality=17)
    i = 1
    while 1:
        print 'Round',i,c.cachesize,c.cuts,c.misses,c.data.keys(); i = i + 1
        c.put(1,2)
        c.get(1)
        c.get(1)
        c.put(5,2)
        c.get(5)
        c.put(2,2)
        c.put(3,2)
        c.get(2)
        c.get(3)
        c.put(2,3)
        c.put(3,'x'*200)
        c.get(2)
        c.get(3)
        c.get(2)
        c.put(4,2)
        c.get(4,2)
        c.get(4,2)
        c.get(4,2)
        # Add noise
        c.put(i,'x')
        c.put(i * 2,'x')
        c.put(i * 3,'x')
        c.get(i)