Changeset 3266

Show
Ignore:
Timestamp:
05/29/07 19:52:59 (1 year ago)
Author:
mscott
Message:

Merge in 'cascade-temp', a short-lived branch to fix circular
reference cascade delete problems.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Schevo/schevo/transaction.py

    r3254 r3266  
    376376 
    377377 
     378def find_chains(entity): 
     379    db = entity.sys.db 
     380    traversed = set() 
     381    chains = [] 
     382    _find_chains(db, entity, traversed, chains) 
     383    return chains 
     384 
     385 
     386def _find_chains(db, entity, traversed, chains, chain=None): 
     387    if chain is None: 
     388        chain = [] 
     389    chain.append(entity) 
     390    if entity in traversed: 
     391        chains.append(chain) 
     392        return 
     393    traversed.add(entity) 
     394    entity_extent_name = entity._extent.name 
     395    for (e_name, f_name), others in entity.sys.links().iteritems(): 
     396        extent = db.extent(e_name) 
     397        for referrer in others: 
     398            _find_chains(db, referrer, traversed, chains, chain) 
     399 
     400 
    378401class Delete(Transaction): 
    379402    """Delete an existing entity instance.""" 
     
    414437                'Original entity revision was %i, is now %i' 
    415438                % (self._rev, entity._rev)) 
     439        deletes = self._deletes 
    416440        # Before execute callback. 
    417441        self._before_execute(db, entity) 
     
    427451        # also requesting cascade deletion. 
    428452        restricter_keys = set(restricters) - set(cascaders) 
     453        # Starting at the entity whose deletion is requested, find 
     454        # chains of circular references that contain that entity, and 
     455        # make sure they are not in the restricters. 
     456        chains = find_chains(entity) 
     457        for chain in chains: 
     458            if chain[0] == entity and chain[0] == chain[-1]: 
     459                chain = frozenset(chain) 
     460                for referrer, restricter_set in restricters.iteritems(): 
     461                    for f_name, referred in frozenset(restricter_set): 
     462                        if referred in chain: 
     463                            restricter_set.remove((f_name, referred)) 
     464                    if len(restricter_set) == 0: 
     465                        restricter_keys.discard(referrer) 
    429466        if len(restricter_keys) != 0: 
    430467            # Raise DeleteRestricted if there are any restricters left 
     
    486523            referrers.add((extent_name, oid, referrer)) 
    487524        # Delete entities in a deterministic (sorted) fashion. 
     525        deletes.add((entity.__class__, entity._oid)) 
    488526        for extent_name, oid, referrer in sorted(referrers): 
    489             if referrer == entity: 
     527            referrer_e_o = referrer.__class__, referrer._oid 
     528            if referrer_e_o in deletes: 
    490529                # Skip the original entity whose deletion was 
    491530                # requested, since we must delete it using a call to 
    492                 # the database's `_delete_entity` method. 
     531                # the database's `_delete_entity` method.  Also skip 
     532                # any entity that has already been deleted. 
    493533                continue 
    494534            if not db._extent_contains_oid(extent_name, oid): 
     
    497537                continue 
    498538            tx = referrer.t.delete() 
     539            tx._deletes.update(deletes) 
    499540            db.execute(tx, strict=False) 
    500541        # Attempt to delete the entity itself. 
  • trunk/Schevo/tests/test_on_delete.py

    r3262 r3266  
    131131 
    132132        bam = f.entity('Bam') 
     133 
     134 
     135    # ---------------------------------------------------------------- 
    133136 
    134137