Changeset 3254
- Timestamp:
- 05/26/07 08:06:33 (1 year ago)
- Files:
-
- trunk/Schevo/doc/SchevoPublicApi.txt (modified) (1 diff)
- trunk/Schevo/schevo/database2.py (modified) (3 diffs)
- trunk/Schevo/schevo/extent.py (modified) (1 diff)
- trunk/Schevo/schevo/transaction.py (modified) (2 diffs)
- trunk/Schevo/tests/test_on_delete.py (modified) (1 diff)
- trunk/Schevo/tests/test_relax_index.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/Schevo/doc/SchevoPublicApi.txt
r3189 r3254 72 72 Extent instances 73 73 ================ 74 75 76 Relaxing and enforcing key restrictions 77 --------------------------------------- 78 79 Schevo has the unique ability to temporarily relax key restrictions 80 while still ensuring that the database remains in a consistent state. 81 82 Key restrictions may only be relaxed within the execution of a 83 transaction. 84 85 Given an extent `db.Foo` that has a key specification of `_key(field1, 86 field2)`, relax that key restriction by calling `relax_index`:: 87 88 db.Foo.relax_index('field1', 'field2') 89 90 Key restrictions that are relaxed within a transaction are relaxed for 91 the entire execution of the transaction, or until the key is enforced 92 within that transaction, or until that transaction ends, whichever 93 comes first. 94 95 When a key restriction is relaxed by a transaction, it remains relaxed 96 for all sub-transactions, regardless of any request by those 97 sub-transactions to enforce the key restriction. 98 99 To re-enforce the key restriction before the end of a transaction's 100 execution, call `enforce_index`:: 101 102 db.Foo.enforce_index('field1', 'field2') 103 104 See the ``tests/test_relax_index.py`` test case for code examples. 74 105 75 106 trunk/Schevo/schevo/database2.py
r3251 r3254 136 136 assert log(2, 'Result was', repr(retval)) 137 137 # Enforce any indices relaxed by the transaction. 138 for extent_name, index_spec in tx._relaxed:138 for extent_name, index_spec in frozenset(tx._relaxed): 139 139 assert log(2, 'Enforcing index', extent_name, index_spec) 140 self._enforce_index (extent_name,index_spec)140 self._enforce_index_field_ids(extent_name, *index_spec) 141 141 # If the transaction must be executed with strict 142 142 # validation, perform that validation now. … … 495 495 496 496 def _enforce_index(self, extent_name, *index_spec): 497 """Call _enforce_index after converting index_spec from field 498 names to field IDs.""" 499 extent_map = self._extent_map(extent_name) 500 index_spec = _field_ids(extent_map, index_spec) 501 return self._enforce_index_field_ids(extent_name, *index_spec) 502 503 def _enforce_index_field_ids(self, extent_name, *index_spec): 497 504 """Validate and begin enforcing constraints on the specified 498 505 index if it was relaxed within the currently-executing … … 502 509 # No-op if called outside a transaction. 503 510 return 504 # ID-ify the index_spec.511 # Find the index to re-enforce. 505 512 extent_map = self._extent_map(extent_name) 506 index_spec = _field_ids(extent_map, index_spec)507 # Find the index to re-enforce.508 513 indices = extent_map['indices'] 509 514 if index_spec not in indices: trunk/Schevo/schevo/extent.py
r2738 r3254 168 168 self._relax(self.name, *index_spec) 169 169 170 def relax_all_indices(self): 171 """Relax all indices using `relax_index`.""" 172 for index_spec in self.key_spec: 173 self.relax_index(*index_spec) 174 170 175 171 176 class ExtentExtenders(NamespaceExtension): trunk/Schevo/schevo/transaction.py
r3245 r3254 11 11 from schevo.constant import (CASCADE, DEFAULT, REMOVE, RESTRICT, 12 12 UNASSIGN, UNASSIGNED) 13 from schevo.error import (DatabaseMismatch, DeleteRestricted, SchemaError, 14 TransactionExpired, TransactionFieldsNotChanged, 15 TransactionNotExecuted) 13 from schevo.error import ( 14 DatabaseMismatch, 15 DeleteRestricted, 16 KeyCollision, 17 SchemaError, 18 TransactionExpired, 19 TransactionFieldsNotChanged, 20 TransactionNotExecuted, 21 ) 16 22 from schevo import field 17 23 from schevo.field import not_fget … … 465 471 field_dump_map.update(new_dump_map) 466 472 field_related_entity_map.update(new_related_entity_map) 467 extent_name = referrer._extent.name 473 extent = referrer._extent 474 extent_name = extent.name 468 475 oid = referrer._oid 469 db._update_entity( 470 extent_name, oid, field_dump_map, field_related_entity_map) 476 try: 477 db._update_entity( 478 extent_name, oid, field_dump_map, field_related_entity_map) 479 except KeyCollision: 480 # Since it takes more time to relax an index, only do 481 # it when we find a key collision. 482 extent.relax_all_indices() 483 # Try the update again. 484 db._update_entity( 485 extent_name, oid, field_dump_map, field_related_entity_map) 471 486 referrers.add((extent_name, oid, referrer)) 472 487 # Delete entities in a deterministic (sorted) fashion. trunk/Schevo/tests/test_on_delete.py
r3233 r3254 541 541 542 542 543 class BaseOnDeleteKeyRelax(CreatesSchema): 544 545 body = """ 546 547 class Foo(E.Entity): 548 549 bar = f.entity('Bar', on_delete=CASCADE) 550 baz = f.entity('Baz', on_delete=CASCADE) 551 552 _key(baz) 553 554 _sample_unittest = [ 555 ((1,), ((1,), 1)), 556 ((1,), ((1,), 2)), 557 ((2,), ((2,), 1)), 558 ((2,), ((2,), 2)), 559 ] 560 561 562 class Bar(E.Entity): 563 564 number = f.integer() 565 566 _key(number) 567 568 _sample_unittest = [ 569 (1,), 570 (2,), 571 ] 572 573 574 class Baz(E.Entity): 575 576 bar = f.entity('Bar', on_delete=CASCADE) 577 number = f.integer() 578 579 _key(bar, number) 580 581 _sample_unittest = [ 582 ((1,), 1), 583 ((1,), 2), 584 ((2,), 1), 585 ((2,), 2), 586 ] 587 588 """ 589 590 def test_delete_bar(self): 591 assert len(db.Foo) == 4 592 assert len(db.Bar) == 2 593 assert len(db.Baz) == 4 594 bar1 = db.Bar.findone(number=1) 595 ex(bar1.t.delete()) 596 assert len(db.Foo) == 2 597 assert len(db.Bar) == 1 598 assert len(db.Baz) == 2 599 600 601 class TestOnDeleteKeyRelax1(BaseOnDeleteKeyRelax): 602 603 format = 1 604 605 606 class TestOnDeleteKeyRelax2(BaseOnDeleteKeyRelax): 607 608 format = 2 609 610 543 611 class TestOnDeleteEntityListRemove(CreatesSchema): 544 612
