Changeset ea373de in trunk for src/allmydata


Ignore:
Timestamp:
2009-10-17T18:00:05Z (16 years ago)
Author:
Brian Warner <warner@…>
Branches:
master
Children:
8a7c980
Parents:
e63f59f
Message:

move dirnode.CachingDict? to dictutil.AuxValueDict?, generalize method names,
improve tests. Let dirnode _pack_children accept either dict or AuxValueDict?.

Location:
src/allmydata
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified src/allmydata/dirnode.py

    re63f59f rea373de  
    2222     LiteralFileURI, from_string
    2323from pycryptopp.cipher.aes import AES
    24 
    25 class CachingDict(dict):
    26     def __init__(self, *args):
    27         super(CachingDict, self).__init__(*args)
    28         self.serialized = {}
    29 
    30     def __setitem__(self, k, v):
    31         super(CachingDict, self).__setitem__(k, v)
    32         self.serialized[k] = None
    33 
    34     def get_both_items(self, k):
    35         return (self.serialized.setdefault(k, None),
    36                 super(CachingDict, self).__getitem__(k))
    37 
    38     def set_both_items(self, key, serialized, t):
    39         self.serialized[key] = serialized
    40         super(CachingDict, self).__setitem__(key, t)
     24from allmydata.util.dictutil import AuxValueDict
    4125
    4226class Deleter:
     
    210194        # an empty directory is serialized as an empty string
    211195        if data == "":
    212             return CachingDict()
     196            return AuxValueDict()
    213197        writeable = not self.is_readonly()
    214         children = CachingDict()
     198        children = AuxValueDict()
    215199        position = 0
    216200        while position < len(data):
     
    229213            metadata = simplejson.loads(metadata_s)
    230214            assert isinstance(metadata, dict)
    231             children.set_both_items(name, entry, (child, metadata))
     215            children.set_with_aux(name, (child, metadata), auxilliary=entry)
    232216        return children
    233217
    234218    def _pack_contents(self, children):
    235219        # expects children in the same format as _unpack_contents
    236         assert isinstance(children, CachingDict)
     220        has_aux = isinstance(children, AuxValueDict)
    237221        entries = []
    238222        for name in sorted(children.keys()):
    239             entry, metadata = children.get_both_items(name)
    240             if entry == None:
    241                 child, metadata = metadata
    242                 assert isinstance(name, unicode)
     223            assert isinstance(name, unicode)
     224            entry = None
     225            if has_aux:
     226                entry = children.get_aux(name)
     227            if not entry:
     228                child, metadata = children.get(name)
    243229                assert IFilesystemNode.providedBy(child), (name,child)
    244230                assert isinstance(metadata, dict)
  • TabularUnified src/allmydata/test/test_dirnode.py

    re63f59f rea373de  
    776776        self.failUnlessEqual(file1_rwcap,
    777777                             children[u'file1'][0].get_uri())
    778 
    779     def test_caching_dict(self):
    780         d = dirnode.CachingDict()
    781         d.set_both_items("test", "test2", ("test3", "test4"))
    782         cached, value = d.get_both_items("test")
    783 
    784         self.failUnlessEqual(cached, "test2")
    785         self.failUnlessEqual(value, ("test3", "test4"))
    786 
    787         d['test'] = ("test3", "test2")
    788 
    789         cached, value = d.get_both_items("test")
    790 
    791         self.failUnlessEqual(cached, None)
    792         self.failUnlessEqual(value, ("test3", "test2"))
    793778
    794779class FakeMutableFile:
  • TabularUnified src/allmydata/test/test_util.py

    re63f59f rea373de  
    12751275        self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
    12761276
     1277    def test_auxdict(self):
     1278        d = dictutil.AuxValueDict()
     1279        # we put the serialized form in the auxdata
     1280        d.set_with_aux("key", ("filecap", "metadata"), "serialized")
     1281
     1282        self.failUnlessEqual(d.keys(), ["key"])
     1283        self.failUnlessEqual(d["key"], ("filecap", "metadata"))
     1284        self.failUnlessEqual(d.get_aux("key"), "serialized")
     1285        def _get_missing(key):
     1286            return d[key]
     1287        self.failUnlessRaises(KeyError, _get_missing, "nonkey")
     1288        self.failUnlessEqual(d.get("nonkey"), None)
     1289        self.failUnlessEqual(d.get("nonkey", "nonvalue"), "nonvalue")
     1290        self.failUnlessEqual(d.get_aux("nonkey"), None)
     1291        self.failUnlessEqual(d.get_aux("nonkey", "nonvalue"), "nonvalue")
     1292
     1293        d["key"] = ("filecap2", "metadata2")
     1294        self.failUnlessEqual(d["key"], ("filecap2", "metadata2"))
     1295        self.failUnlessEqual(d.get_aux("key"), None)
     1296
     1297        d.set_with_aux("key2", "value2", "aux2")
     1298        self.failUnlessEqual(sorted(d.keys()), ["key", "key2"])
     1299        del d["key2"]
     1300        self.failUnlessEqual(d.keys(), ["key"])
     1301        self.failIf("key2" in d)
     1302        self.failUnlessRaises(KeyError, _get_missing, "key2")
     1303        self.failUnlessEqual(d.get("key2"), None)
     1304        self.failUnlessEqual(d.get_aux("key2"), None)
     1305        d["key2"] = "newvalue2"
     1306        self.failUnlessEqual(d.get("key2"), "newvalue2")
     1307        self.failUnlessEqual(d.get_aux("key2"), None)
     1308
     1309        d = dictutil.AuxValueDict({1:2,3:4})
     1310        self.failUnlessEqual(sorted(d.keys()), [1,3])
     1311        self.failUnlessEqual(d[1], 2)
     1312        self.failUnlessEqual(d.get_aux(1), None)
     1313
     1314        d = dictutil.AuxValueDict([ (1,2), (3,4) ])
     1315        self.failUnlessEqual(sorted(d.keys()), [1,3])
     1316        self.failUnlessEqual(d[1], 2)
     1317        self.failUnlessEqual(d.get_aux(1), None)
     1318
     1319        d = dictutil.AuxValueDict(one=1, two=2)
     1320        self.failUnlessEqual(sorted(d.keys()), ["one","two"])
     1321        self.failUnlessEqual(d["one"], 1)
     1322        self.failUnlessEqual(d.get_aux("one"), None)
     1323
    12771324class Pipeline(unittest.TestCase):
    12781325    def pause(self, *args, **kwargs):
  • TabularUnified src/allmydata/util/dictutil.py

    re63f59f rea373de  
    606606        del self.d[le[1]]
    607607        return le[1]
     608
     609class AuxValueDict(dict):
     610    """I behave like a regular dict, but each key is associated with two
     611    values: the main value, and an auxilliary one. Setting the main value
     612    (with the usual d[key]=value) clears the auxvalue. You can set both main
     613    and auxvalue at the same time, and can retrieve the values separately.
     614
     615    The main use case is a dictionary that represents unpacked child values
     616    for a directory node, where a common pattern is to modify one or more
     617    children and then pass the dict back to a packing function. The original
     618    packed representation can be cached in the auxvalue, and the packing
     619    function can use it directly on all unmodified children. On large
     620    directories with a complex packing function, this can save considerable
     621    time."""
     622
     623    def __init__(self, *args, **kwargs):
     624        super(AuxValueDict, self).__init__(*args, **kwargs)
     625        self.auxilliary = {}
     626
     627    def __setitem__(self, key, value):
     628        super(AuxValueDict, self).__setitem__(key, value)
     629        self.auxilliary[key] = None # clear the auxvalue
     630
     631    def __delitem__(self, key):
     632        super(AuxValueDict, self).__delitem__(key)
     633        self.auxilliary.pop(key)
     634
     635    def get_aux(self, key, default=None):
     636        """Retrieve the auxilliary value. There is no way to distinguish
     637        between an auxvalue of 'None' and a key that does not have an
     638        auxvalue, and get_aux() will not raise KeyError when called with a
     639        missing key."""
     640        return self.auxilliary.get(key, default)
     641
     642    def set_with_aux(self, key, value, auxilliary):
     643        """Set both the main value and the auxilliary value. There is no way
     644        to distinguish between an auxvalue of 'None' and a key that does not
     645        have an auxvalue."""
     646        super(AuxValueDict, self).__setitem__(key, value)
     647        self.auxilliary[key] = auxilliary
Note: See TracChangeset for help on using the changeset viewer.