Changeset 7082


Ignore:
Timestamp:
Feb 26, 2016, 9:27:02 AM (6 years ago)
Author:
Nicklas Nordborg
Message:

References #1148: Removing items from trashcan when circular references exists

Implemented code for breaking circular references in the following cases:

  • Any-to-any links. This is done by the trashcan code.
  • User->Home directory.
  • Biomaterial->Biomaterial.
  • Derived bioassay->Derived bioassay.


Groups can also have circular references to other groups but that is resolved by cascade delete in Hibernate.

Right now I can't think of any more places that can result in circular references.

Location:
trunk/src/core
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/core/common-queries.xml

    r7015 r7082  
    20972097    </description>
    20982098  </query>
     2099 
     2100  <query id="DELETE_ALL_ANYTOANY_TO" type="HQL">
     2101    <sql>
     2102      DELETE FROM AnyToAnyData ata
     2103      WHERE ata.toId = :toId AND ata.toType = :toType
     2104    </sql>
     2105    <description>
     2106      A Hibernate query that deletes all any-to-any links leading in to an item.
     2107    </description>
     2108  </query>
    20992109
    21002110  <query id="DELETE_UNUSED_ANYTOANY_TO" type="HQL">
  • trunk/src/core/net/sf/basedb/core/BasicItem.java

    r7002 r7082  
    267267  }
    268268
     269  /**
     270    Break references to items that may lead to circular references.
     271    This method is intended to be implemented by subclasses and should
     272    only break references leading to items that are found in the
     273    given set of items. This method is called from the {@link Trashcan}
     274    which has already confirmed that the given items are about to
     275    be deleted and may have circular references between them.
     276    NOTE! This method should not check {@link AnyToAny} links. This has
     277    already been done in the trashcan code.
     278    @since 3.8
     279  */
     280  int breakCircularReferences(Set<ItemProxy> items)
     281  {
     282    return 0;
     283  }
     284 
    269285  /**
    270286    Add items to the set of items using this one.
  • trunk/src/core/net/sf/basedb/core/DerivedBioAssay.java

    r7003 r7082  
    272272  }
    273273 
     274  /**
     275    Any parent bioassays found among the given items are removed from
     276    this item. NOTE! Due to {@link FixDerivedBioAssayParentsRecursivelyAction}
     277    it should not be possible to create circular references between derived
     278    bioassays, but in case something changes in the future we have implemented
     279    this method anyway.
     280    @since 3.8
     281  */
     282  @Override
     283  int breakCircularReferences(Set<ItemProxy> items)
     284  {
     285    int removed = super.breakCircularReferences(items);
     286    DbControl dc = getDbControl();
     287    Set<DerivedBioAssayData> parents = getData().getParents();
     288    for (ItemProxy p : items)
     289    {
     290      if (DerivedBioAssay.class.isAssignableFrom(p.getType().getItemClass()))
     291      {
     292        DerivedBioAssay dba = (DerivedBioAssay)p.getItem(dc);
     293        if (parents.remove(dba.getData()))
     294        {
     295          removed++;
     296        }
     297      }
     298    }
     299    return removed;
     300  }
     301
    274302  /**
    275303    Automatically try to assign an extract from parent items at
  • trunk/src/core/net/sf/basedb/core/MeasuredBioMaterial.java

    r7003 r7082  
    131131    addUsingItems(using, query);
    132132    return using;
     133  }
     134
     135  /**
     136    Any parent items found among the given items are removed from
     137    the creation event of this item.
     138    @since 3.8
     139  */
     140  @Override
     141  int breakCircularReferences(Set<ItemProxy> items)
     142  {
     143    int removed = super.breakCircularReferences(items);
     144    BioMaterialEvent creationEvent = getCreationEvent();
     145    DbControl dc = getDbControl();
     146    for (ItemProxy p : items)
     147    {
     148      if (BioMaterial.class.isAssignableFrom(p.getType().getItemClass()))
     149      {
     150        BioMaterial bm = (BioMaterial)p.getItem(dc);
     151        if (creationEvent.isSource(bm))
     152        {
     153          creationEvent.removeSource(bm);
     154          removed++;
     155        }
     156      }
     157    }
     158    return removed;
    133159  }
    134160
  • trunk/src/core/net/sf/basedb/core/Trashcan.java

    r7080 r7082  
    225225    int numRemoved = 0;
    226226    int removedInTransaction = 0;
     227    boolean hasBrokenCircularReferences = false;
    227228    int projectId = sc.getActiveProjectId();
    228229
     
    300301        }
    301302       
    302         if (removedInTransaction == 0 && itemsToRemove.size() > 0)
     303        if (removedInTransaction == 0 && itemsToRemove.size() > 0 && !hasBrokenCircularReferences)
    303304        {
    304305          // Not all items could be removed, try to break circular references
    305306          // Note that as a (desired) side-effect non-removable items will be
    306307          // removed from 'itemsToRemove'
     308          hasBrokenCircularReferences = true; // No need to do this twice
    307309          removedInTransaction = breakCircularReferences(sc2, itemsToRemove);
    308310          if (isDebug)
    309311          {
    310312            log.debug("Removed " + removedInTransaction + " circular references; " +
    311               itemsToRemove.size() + " remains in list");
     313              itemsToRemove.size() + " items remains in list");
    312314          }
    313315        }
     
    423425      if (isDebug) log.debug(itemsToRemove.size() + " remaining items with circular ref: " + itemsToRemove);
    424426     
    425       // Break circular references
    426       for (CircularRefInfo c : cRef)
    427       {
    428         circularRefsBroken += c.breakReferences(dc, itemsToRemove);
     427      if (itemsToRemove.size() > 0)
     428      {
     429        // Query for breaking AnyToAnyLinks between items
     430        org.hibernate.Query query = HibernateUtil.getPredefinedQuery(dc.getHibernateSession(),
     431          "DELETE_ALL_ANYTOANY_TO");
     432        /*
     433          DELETE FROM AnyToAnyData ata
     434          WHERE ata.toId = :toId AND ata.toType = :toType
     435        */
     436        // Break circular references
     437        for (CircularRefInfo c : cRef)
     438        {
     439          query.setInteger("toId", c.proxy.getId());
     440          query.setInteger("toType", c.proxy.getType().getValue());
     441          int brokenAnyToAny = query.executeUpdate();
     442          int brokenRefs = c.proxy.getItem(dc).breakCircularReferences(itemsToRemoveProxy);
     443          if (isDebug)
     444          {
     445            log.debug(c.item + ": " + brokenRefs + " broken references; " +
     446              brokenAnyToAny + " broken any-to-any links");
     447          }
     448          circularRefsBroken += brokenAnyToAny + brokenRefs;
     449        }
    429450      }
    430451     
    431452      dc.commit();
    432          
    433453    }
    434454    finally
     
    481501    }
    482502   
    483     /**
    484       Break all references from this item to the items in itemsToRemove.
    485       @return The number of references broken
    486     */
    487     int breakReferences(DbControl dc, Set<Identifiable> itemsToRemove)
    488     {
    489       // TODO
    490       return 0;
    491     }
    492    
    493    
    494503  }
    495504 
  • trunk/src/core/net/sf/basedb/core/User.java

    r7038 r7082  
    435435  }
    436436 
     437  /**
     438    If the home directory is found among the items, set it to null.
     439    @since 3.8
     440  */
     441  @Override
     442  int breakCircularReferences(Set<ItemProxy> items)
     443  {
     444    int removed = super.breakCircularReferences(items);
     445    DirectoryData hd = getData().getHomeDirectory();
     446    if (hd != null)
     447    {
     448      if (items.contains(new ItemProxy(hd.getId(), Item.DIRECTORY)))
     449      {
     450        getData().setHomeDirectory(null);
     451        removed++;
     452      }
     453    }
     454    return removed;
     455  }
     456
    437457 
    438458  /**
     
    13361356    }
    13371357  }
     1358
    13381359}
    13391360
Note: See TracChangeset for help on using the changeset viewer.