Changeset 577
- Timestamp:
- 11/06/07 13:05:26
- Files:
-
- branches/crazycache/dejavu/storage/caching.py (modified) (1 diff)
- branches/crazycache/dejavu/storage/storememcached.py (modified) (12 diffs)
- branches/crazycache/dejavu/test/zoo_fixture.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/crazycache/dejavu/storage/caching.py
r575 r577 94 94 # Try to retrieve units using a cached index. 95 95 if cls.identifiers and cls in self.cache.classes: 96 units = self.cache.scan(self.nextstore, cls, expr) 97 if units is not None: 98 units = [(unit,) for unit in units] 99 for unit in self._paginate(units, order, limit, offset, single=True): 100 yield unit 101 return 96 if hasattr(self.cache, 'scan'): 97 units = self.cache.scan(self.nextstore, cls, expr) 98 if units is not None: 99 units = [(unit,) for unit in units] 100 for unit in self._paginate(units, order, limit, offset, 101 single=True): 102 yield unit 103 return 102 104 103 105 # Query storage. branches/crazycache/dejavu/storage/storememcached.py
r575 r577 386 386 unit = self.client.get(key) 387 387 if unit is not None: 388 unit.cleanse() 388 389 units.append(unit) 389 390 return units … … 513 514 keyattrs = self.primary_keys[cls] 514 515 515 # Get a cached list of identifier-tuples.516 # Find the best index for the given filters. 516 517 for index in indexset: 517 518 if set(filters.keys()) >= set(index): 518 indexcriteria = dict([(k, filters[k]) for k in index])519 519 break 520 520 else: … … 522 522 return None 523 523 524 ids = indexset.get(indexcriteria) 524 criteria = [(k, filters[k]) for k in index] 525 ids = indexset.get(criteria) 525 526 if ids is None: 526 527 # Not in the cache. Grab the list of id-tuples from nextstore. 527 ids = mainstore.view((cls, keyattrs, filters)) 528 # Note well: we're NOT grabbing view(.., filters), because 529 # if filters > criteria, that would cache a subset of 530 # the index leaf node. 531 ids = mainstore.view((cls, keyattrs, dict(criteria))) 528 532 # Then cache the list result for next time. Note that index 529 533 # contents are unordered. 530 indexset.put(indexcriteria, ids, time=self.index_time) 531 532 # Query the cache for multiple units (by id). 533 units = indexset.scan(ids) 534 misses = [k for k in ids if k not in units] 535 else: 536 # Query the cache for multiple units (by id). 537 units = indexset.scan(ids) 538 539 # Remove any idents from the index node that no longer 540 # satisfy the index criteria. This is how we update 541 # index nodes--eager adds but late discards. 542 removals = False 543 for id, unit in units.items(): 544 for key, value in filters.iteritems(): 545 if getattr(unit, key) != value: 546 removals = True 547 del units[id] 548 ids.remove(id) 549 break 550 if removals: 551 indexset.put(indexcriteria, ids, time=self.index_time) 552 553 misses = [k for k in ids if k not in units] 534 indexset.put(criteria, ids, time=self.index_time) 535 536 # Query the cache for multiple units (by id). 537 units = indexset.scan(ids) 554 538 555 539 # Now query the nextstore for any units that the cache missed... 540 misses = [k for k in ids if k not in units] 556 541 if self.index_stride: 557 542 # ...in chunks of length: self.index_stride. … … 580 565 pass 581 566 567 indexset.filter(index, filters, units) 568 582 569 return units.values() 583 570 … … 614 601 return iter(self.indices) 615 602 616 def key(self, filters): 617 """Return the cache key for the given filters. 618 619 If filters is an empty dict, the 'global index' key is returned. 603 def key(self, criteria): 604 """Return the cache key for the index node for the given criteria. 605 606 The given criteria must be an iterable of (key, value) tuples, 607 and must only contain keys for an existing index. 608 609 If criteria is an empty list, the 'global index' key is returned. 620 610 """ 621 611 criteria = ["%s=%s" % (k, str(v).replace(" ", "+")) 622 for k, v in filters.iteritems()]612 for k, v in criteria] 623 613 return self._key_template % ",".join(criteria) 624 614 625 def get(self, filters): 626 """Return a cached list of unit ids which match the given filters dict. 615 def get(self, criteria): 616 """Return a cached list of unit ids which match the given criteria. 617 618 The given criteria must be an iterable of (key, value) tuples, 619 and must only contain keys for an existing index. 620 621 If criteria is an empty list, the 'global index' key is returned. 627 622 628 623 The ids returned will be a list of tuples of the form: 629 624 tuple([getattr(unit, name) for name in primary_keys[cls]]) 630 625 """ 631 cache_key = self.key( filters)626 cache_key = self.key(criteria) 632 627 ids = self.store.client.get(cache_key) 633 628 if self.store.logflags & logflags.IO: … … 640 635 return ids 641 636 642 def put(self, filters, ids, time=0): 643 """Cache a list of unit identifiers which match the given filters dict. 637 def put(self, criteria, ids, time=0): 638 """Cache a list of unit identifiers which match the given criteria. 639 640 The given criteria must be an iterable of (key, value) tuples, 641 and must only contain keys for an existing index. 642 643 If criteria is an empty list, the 'global index' key is returned. 644 644 645 645 The ids provided MUST be a list of tuples of the form: 646 646 tuple([getattr(unit, name) for name in primary_keys[cls]]) 647 647 """ 648 cache_key = self.key( filters)648 cache_key = self.key(criteria) 649 649 if self.store.logflags & logflags.IO: 650 650 self.store.log(logflags.IO.message("INDEX PUT (%s) len %r: %r" % … … 658 658 tuple([getattr(unit, name) for name in primary_keys[cls]]) 659 659 660 The returned dict will not contain entries for missed ids. 660 The returned dict will not contain entries for any units which 661 have expired from the cache. Callers may use this information 662 to request missed units from another store. 661 663 """ 662 664 clsname = self.cls.__name__ … … 671 673 unit = data.get(k, None) 672 674 if unit is not None: 675 unit.cleanse() 673 676 units[i] = unit 674 677 else: … … 694 697 # to perform single gets against memcached, rather than the 695 698 # get_multi calls that self.xrecall performs. 696 indexcriteria = dict([(k, filters[k]) for k in index])697 ids = self.get( indexcriteria)699 criteria = [(k, filters[k]) for k in index] 700 ids = self.get(criteria) 698 701 if ids: 699 702 for id in ids: … … 722 725 index, although it may and often should contain additional entries. 723 726 """ 724 indexcriteria = dict([(k, filters[k]) for k in index])725 ids = self.get( indexcriteria)727 criteria = [(k, filters[k]) for k in index] 728 ids = self.get(criteria) 726 729 if ids: 727 730 units = self.scan(ids) 728 729 removals = False 730 for id, unit in units.items(): 731 for k, v in filters.iteritems(): 732 if getattr(unit, k) != v: 733 if k in index: 734 removals = True 735 del units[id] 736 ids.remove(id) 737 break 738 else: 739 unit.cleanse() 740 yield unit 741 742 if removals: 743 # Remove any idents from the index node that no longer 744 # satisfy the index criteria. This is how we update 745 # index nodes--eager adds but late discards. 746 self.put(indexcriteria, ids, time=self.store.index_time) 731 self.filter(index, filters, units) 732 for unit in units.itervalues(): 733 unit.cleanse() 734 yield unit 735 736 def filter(self, index, filters, units): 737 """Remove any units which don't match filters, and update the index. 738 739 The filters argument must contain an entry for each key in the given 740 index, although it may and often should contain additional entries. 741 742 The 'units' arg must be a dict of (id, unit) pairs, and must be 743 the complete set of units from an index node; that is, the result 744 of an indexset.get() call for the same index. 745 """ 746 ids = units.keys() 747 removals = False 748 for id, unit in units.items(): 749 for key, value in filters.iteritems(): 750 if getattr(unit, key) != value: 751 del units[id] 752 # Remove any idents from the index node that no longer 753 # satisfy the index criteria. This is how we update 754 # index nodes--eager adds but late discards. 755 if key in index: 756 removals = True 757 ids.remove(id) 758 if removals: 759 criteria = [(k, filters[k]) for k in index] 760 indexset.put(criteria, ids, time=self.store.index_time) 747 761 748 762 def add(self, unit): … … 751 765 for name in self.store.primary_keys[self.cls]]) 752 766 for index in self.indices: 753 indexcriteria = dict([(k, getattr(unit, k)) for k in index])754 indexnode = self.get( indexcriteria) or []767 criteria = [(k, getattr(unit, k)) for k in index] 768 indexnode = self.get(criteria) or [] 755 769 if ident not in indexnode: 756 770 indexnode.append(ident) 757 self.put( indexcriteria, indexnode)771 self.put(criteria, indexnode) 758 772 759 773 def discard(self, unit): … … 762 776 for name in self.store.primary_keys[self.cls]]) 763 777 for index in self.indices: 764 indexcriteria = dict([(k, getattr(unit, k)) for k in index])765 indexnode = self.get( indexcriteria) or []778 criteria = [(k, getattr(unit, k)) for k in index] 779 indexnode = self.get(criteria) or [] 766 780 if ident in indexnode: 767 781 indexnode.remove(ident) 768 self.put( indexcriteria, indexnode)769 782 self.put(criteria, indexnode) 783 branches/crazycache/dejavu/test/zoo_fixture.py
r567 r577 62 62 63 63 class Animal(Unit): 64 Class = UnitProperty(index=True) 64 65 Species = UnitProperty(hints={'bytes': 100}) 65 66 ZooID = UnitProperty(int, index=True) … … 256 257 257 258 # Animals 258 leopard = Animal( Species='Leopard', Lifespan=73.5)259 leopard = Animal(Class='Mammalia', Species='Leopard', Lifespan=73.5) 259 260 self.assertEqual(leopard.PreviousZoos, None) 260 261 box.memorize(leopard) … … 264 265 leopard.LastEscape = datetime.datetime(2004, 12, 21, 8, 15, 0, 999907) 265 266 266 lion = Animal( Species='Lion', ZooID=WAP.ID,267 lion = Animal(Class='Mammalia', Species='Lion', ZooID=WAP.ID, 267 268 LastEscape = datetime.datetime(2007, 9, 24, 268 269 16, 18, 42)) 269 270 box.memorize(lion) 270 271 271 box.memorize(Animal(Species='Slug', Legs=1, Lifespan=.75, 272 box.memorize(Animal(Class='Gastropoda', Species='Slug', 273 Legs=1, Lifespan=.75, 272 274 # Test our 8000-byte limit 273 275 PreviousZoos=["f" * (8000 - 14)])) 274 276 275 tiger = Animal(Species='Tiger', PreviousZoos=['animal\\universe']) 277 tiger = Animal(Class='Mammalia', Species='Tiger', 278 PreviousZoos=['animal\\universe']) 276 279 box.memorize(tiger) 277 280 278 281 # Override Legs.default with itself just to make sure it works. 279 box.memorize(Animal( Species='Bear', Legs=4))282 box.memorize(Animal(Class='Mammalia', Species='Bear', Legs=4)) 280 283 # Notice that ostrich.PreviousZoos is [], whereas leopard is None. 281 box.memorize(Animal(Species='Ostrich', Legs=2, PreviousZoos=[], 284 box.memorize(Animal(Class='Aves', Species='Ostrich', 285 Legs=2, PreviousZoos=[], 282 286 Lifespan=103.2)) 283 box.memorize(Animal( Species='Centipede', Legs=100))284 285 emp = Animal( Species='Emperor Penguin', Legs=2)287 box.memorize(Animal(Class='Chilopoda', Species='Centipede', Legs=100)) 288 289 emp = Animal(Class='Aves', Species='Emperor Penguin', Legs=2) 286 290 box.memorize(emp) 287 adelie = Animal( Species='Adelie Penguin', Legs=2,291 adelie = Animal(Class='Aves', Species='Adelie Penguin', Legs=2, 288 292 LastEscape = datetime.datetime(2007, 9, 20, 289 293 19, 10, 14)) … … 292 296 seaworld.add(emp, adelie) 293 297 294 millipede = Animal( Species='Millipede', Legs=1000000)298 millipede = Animal(Class='Diplopoda', Species='Millipede', Legs=1000000) 295 299 millipede.PreviousZoos = [WAP.Name] 296 300 box.memorize(millipede) … … 299 303 300 304 # Add a mother and child to test relationships 301 bai_yun = Animal( Species='Ape', Legs=2)305 bai_yun = Animal(Class='Mammalia', Species='Ape', Legs=2) 302 306 box.memorize(bai_yun) # ID = 11 303 307 self.assertEqual(bai_yun.ID, 11) 304 hua_mei = Animal(Species='Ape', Legs=2, MotherID=bai_yun.ID) 308 hua_mei = Animal(Class='Mammalia', Species='Ape', Legs=2, 309 MotherID=bai_yun.ID) 305 310 box.memorize(hua_mei) # ID = 12 306 311 self.assertEqual(hua_mei.ID, 12) … … 539 544 finally: 540 545 box.flush_all() 546 547 def test_4a_Indexing(self): 548 # Different subsets of an index leaf node must return correct data. 549 for legs, species in [(2, set(['Ape', 'Ape'])), 550 (4, set(['Leopard', 'Lion', 'Tiger', 'Bear']))]: 551 animals = root.recall(Animal, dict(Class='Mammalia', Legs=legs)) 552 self.assertEqual(set([a.Species for a in animals]), species) 541 553 542 554 def test_5_Aggregates(self):
