From: Patrick B. <pat...@jo...> - 2011-11-03 19:58:57
|
Hi everyone, *eXist/stable - 1.4.x I've been working on a locking issue that was caused by NativeBroker.openCollection(..) on line 699, and I think I have a solution. Below is what I have changed the function too. I've tested it pretty thoroughly and it seems to run well, but being such a core part of the database I think it's important that it's reviewed before I commit it into the code base. private Collection openCollection(XmldbURI uri, long addr, int lockMode) { uri = prepend(uri.toCollectionPathURI()); //We *must* declare it here (see below) Collection collection; final CollectionCache collectionsCache = pool.getCollectionsCache(); synchronized(collectionsCache) { collection = collectionsCache.get(uri); if(collection != null) { if (!collection.getURI().equalsInternal(uri)) { LOG.error("The collection received from the cache is not the requested: " + uri + "; received: " + collection.getURI()); } synchronized(collectionsCache) { collectionsCache.add(collection); } } } if (collection == null) { final Lock lock = collectionsDb.getLock(); try{ lock.acquire(Lock.READ_LOCK); try { VariableByteInput is; if (addr == BFile.UNKNOWN_ADDRESS) { Value key = new CollectionStore.CollectionKey(uri.toString()); is = collectionsDb.getAsStream(key); } else { is = collectionsDb.getAsStream(addr); } if (is == null) return null; collection = new Collection(uri); collection.read(this, is); //TODO : manage this from within the cache -pb if(!pool.isInitializing()) synchronized(collectionsCache) { /* * This is here on the off chance this collection was loaded by another * thread in the time we were loading it. We'll take theirs. */ Collection tempTestCollection = collectionsCache.get(uri); if (tempTestCollection != null) collection = tempTestCollection; collectionsCache.add(collection); } //TODO : rethrow exceptions ? -pb } catch (UnsupportedEncodingException e) { LOG.error("Unable to encode '" + uri + "' in UTF-8"); return null; } catch (IOException e) { LOG.error(e.getMessage(), e); return null; } finally { lock.release(Lock.READ_LOCK); } } catch (LockException e) { LOG.warn("Failed to acquire lock on " + collectionsDb.getFile().getName()); return null; } } //Important : //This code must remain ouside of the synchonized block //because another thread may already own a lock on the collection //This would result in a deadlock... until the time-out raises the Exception //TODO : make an attempt to an immediate lock ? //TODO : manage a collection of requests for locks ? //TODO : another yet smarter solution ? if(lockMode != Lock.NO_LOCK) { try { collection.getLock().acquire(lockMode); } catch (LockException e) { LOG.warn("Failed to acquire lock on collection '" + uri + "'"); } } return collection; } -- Patrick Bosek Jorsek Software Cell (585) 820 9634 Office (877) 492 2960 Jorsek.com |