Changeset 6509


Ignore:
Timestamp:
Aug 8, 2014, 11:32:09 AM (8 years ago)
Author:
Nicklas Nordborg
Message:

Fixes #1828: Calling Directory.getNew() multiple times with overlapping non-existing paths

A thread-local cache of directories that has already been created in the current transaction are used to keep track so that the same directory is not created multiple times.

Location:
branches/3.3-stable/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/3.3-stable/src/core/net/sf/basedb/core/Directory.java

    r6127 r6509  
    2929import net.sf.basedb.core.query.Restrictions;
    3030
     31import java.util.HashMap;
    3132import java.util.LinkedList;
     33import java.util.Map;
    3234import java.util.Set;
    3335
     
    106108  }
    107109
     110  private static ThreadLocal<Map<String, Directory>> DIRECTORY_CACHE = new ThreadLocal<Map<String,Directory>>()
     111  {
     112    @Override
     113    protected Map<String, Directory> initialValue()
     114    {
     115      return new HashMap<String, Directory>();
     116    }
     117  };
     118 
    108119  /**
    109120    Create a new or existing <code>Directory</code> from a path. Every
     
    137148    Directory currentDir = null;
    138149    boolean creating = false;
     150    String currentPath = "";
     151    Map<String, Directory> directoryCache = null;
     152   
    139153    org.hibernate.Query query = HibernateUtil.getPredefinedQuery(
    140154        dc.getHibernateSession(), "GET_SUBDIRECTORY_WITH_NAME");
     
    148162    {
    149163      String subDirName = path.getDirectory(i);
     164      currentPath +="/" + subDirName;
    150165      if (!creating)
    151166      {
     
    168183      if (creating)
    169184      {
    170         // This must be permission checked
    171         Directory newSubDir = currentDir.newSubDirectory();
    172         newSubDir.setName(subDirName);
    173         dc.saveItem(newSubDir);
    174         currentDir = newSubDir;
     185        directoryCache = DIRECTORY_CACHE.get();
     186        if (directoryCache.size() == 0)
     187        {
     188          // Clean up when transaction is about to complete
     189          dc.addTransactionalAction(
     190            new TransactionalAction()
     191            {
     192              @Override
     193              public void onRollback()
     194              {}
     195             
     196              @Override
     197              public void onBeforeCommit()
     198              {
     199                DIRECTORY_CACHE.remove();
     200              }
     201             
     202              @Override
     203              public void onAfterCommit()
     204              {}
     205            }
     206          );
     207        }
     208        // Check cache if we have already created the subdir
     209        if (directoryCache.containsKey(currentPath))
     210        {
     211          currentDir = directoryCache.get(currentPath);
     212        }
     213        else
     214        {
     215          // This must be permission checked
     216          Directory newSubDir = currentDir.newSubDirectory();
     217          newSubDir.setName(subDirName);
     218          dc.saveItem(newSubDir);
     219          currentDir = newSubDir;
     220          directoryCache.put(currentPath, currentDir);
     221        }
    175222      }
    176223    }
  • branches/3.3-stable/src/test/TestDirectory.java

    r6508 r6509  
    6565    test_list(id1);
    6666   
    67     int[] pid = test_create_multiple("/foo", "/foo/bar1", "/foo/bar2", "/foo/bar1/sub1");
     67    int[] pid = test_create_multiple("/foo", "/foo/bar1", "/foo/bar2", "/foo/bar1/sub1", "/foo/bar2/sub1", "/foo/bar2/sub2");
    6868   
    6969    if (TestUtil.waitBeforeDelete()) TestUtil.waitForEnter();
     
    153153  {
    154154    if (!TestUtil.hasPermission(Permission.CREATE, Item.DIRECTORY)) return null;
     155    Directory d[] = new Directory[path.length];
    155156    int id[] = new int[path.length];
    156157    DbControl dc = null;
     
    161162      {
    162163        Path p = new Path(path[i], Path.Type.DIRECTORY);
    163         Directory d = Directory.getNew(dc, p);
    164         write_item(i, d);
    165         id[i] = d.getId();
     164        d[i] = Directory.getNew(dc, p);
    166165      }
    167166      dc.commit();
     167     
     168      // Copy id values
     169      dc = TestUtil.getDbControl();
     170      for (int i = 0; i < path.length; i++)
     171      {
     172        id[i] = d[i].getId();
     173        dc.reattachItem(d[i], false);
     174        write_item(i, d[i]);
     175      }
     176     
    168177      write("--Create multiple by path OK");
    169178    }
Note: See TracChangeset for help on using the changeset viewer.