From: Wolfgang M. M. <wol...@us...> - 2004-07-28 18:55:42
|
Update of /cvsroot/exist/eXist-1.0/src/org/exist/storage In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4115/src/org/exist/storage Modified Files: BrokerPool.java DBBroker.java NativeBroker.java Log Message: * Fixed locking error: a collection object could be unloaded from the cache by one thread, while another thread had still been writing a document being a member of the collection. A moment later, a third thread reloaded the collection and started to write to the same document. However, as the collection had been recreated, there were two instances of the same document in memory. The third thread did thus not respect the lock held by the first thread and started to write without waiting. As a consequence, various page errors were thrown. * When updating a document, the old document metadata had not been correctly removed. Usually, this had no consequences as the collection class only used the last record it found. In some cases however, this may have led to errors. Index: NativeBroker.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/storage/NativeBroker.java,v retrieving revision 1.90 retrieving revision 1.91 diff -C2 -d -r1.90 -r1.91 *** NativeBroker.java 23 Jul 2004 14:19:52 -0000 1.90 --- NativeBroker.java 28 Jul 2004 18:54:55 -0000 1.91 *************** *** 1340,1344 **** LOG.debug("Checking document " + doc.getFileName()); checkTree(doc); ! elementIndex.consistencyCheck(doc); } } --- 1340,1344 ---- LOG.debug("Checking document " + doc.getFileName()); checkTree(doc); ! // elementIndex.consistencyCheck(doc); } } *************** *** 1346,1381 **** public void checkTree(final DocumentImpl doc) { LOG.debug("Checking DOM tree for document " + doc.getFileName()); ! new DOMTransaction(this, domDb, Lock.READ_LOCK) { ! public Object start() throws ReadOnlyException { ! LOG.debug("Pages used: " + domDb.debugPages(doc)); ! return null; } ! }.run(); ! ! NodeList nodes = doc.getChildNodes(); ! NodeImpl n; ! for (int i = 0; i < nodes.getLength(); i++) { ! n = (NodeImpl) nodes.item(i); ! Iterator iterator = ! getNodeIterator( ! new NodeProxy(doc, n.getGID(), n.getInternalAddress())); ! iterator.next(); ! checkTree(iterator, n); ! } ! NodeRef ref = new NodeRef(doc.getDocId()); ! final IndexQuery idx = new IndexQuery(IndexQuery.TRUNC_RIGHT, ref); ! new DOMTransaction(this, domDb) { ! public Object start() { ! try { ! domDb.findKeys(idx); ! } catch (BTreeException e) { ! LOG.warn("start() - " + "error while removing doc", e); ! } catch (IOException e) { ! LOG.warn("start() - " + "error while removing doc", e); } - return null; } } - .run(); } --- 1346,1383 ---- public void checkTree(final DocumentImpl doc) { LOG.debug("Checking DOM tree for document " + doc.getFileName()); ! if(xupdateConsistencyChecks) { ! new DOMTransaction(this, domDb, Lock.READ_LOCK) { ! public Object start() throws ReadOnlyException { ! LOG.debug("Pages used: " + domDb.debugPages(doc)); ! return null; ! } ! }.run(); ! ! NodeList nodes = doc.getChildNodes(); ! NodeImpl n; ! for (int i = 0; i < nodes.getLength(); i++) { ! n = (NodeImpl) nodes.item(i); ! Iterator iterator = ! getNodeIterator( ! new NodeProxy(doc, n.getGID(), n.getInternalAddress())); ! iterator.next(); ! checkTree(iterator, n); } ! NodeRef ref = new NodeRef(doc.getDocId()); ! final IndexQuery idx = new IndexQuery(IndexQuery.TRUNC_RIGHT, ref); ! new DOMTransaction(this, domDb) { ! public Object start() { ! try { ! domDb.findKeys(idx); ! } catch (BTreeException e) { ! LOG.warn("start() - " + "error while removing doc", e); ! } catch (IOException e) { ! LOG.warn("start() - " + "error while removing doc", e); ! } ! return null; } } + .run(); } } *************** *** 2383,2386 **** --- 2385,2389 ---- } doc.setAddress(domDb.add(data)); + // LOG.debug("Document metadata stored to " + StorageAddress.toString(doc.getAddress())); return null; } *************** *** 2389,2392 **** --- 2392,2406 ---- } + public void updateDocument(DocumentImpl doc) throws LockException, PermissionDeniedException { + Lock lock = collectionsDb.getLock(); + try { + lock.acquire(Lock.WRITE_LOCK); + storeDocument(doc); + saveCollection(doc.getCollection()); + } finally { + lock.release(); + } + } + public void storeBinaryResource(final BinaryDocument blob, final byte[] data) { new DOMTransaction(this, domDb, Lock.WRITE_LOCK) { *************** *** 2402,2406 **** .run(); } ! public byte[] getBinaryResourceData(final BinaryDocument blob) { byte[] data = (byte[]) new DOMTransaction(this, domDb, Lock.WRITE_LOCK) { --- 2416,2420 ---- .run(); } ! public byte[] getBinaryResourceData(final BinaryDocument blob) { byte[] data = (byte[]) new DOMTransaction(this, domDb, Lock.WRITE_LOCK) { Index: DBBroker.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/storage/DBBroker.java,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -d -r1.38 -r1.39 *** DBBroker.java 19 Jul 2004 13:06:24 -0000 1.38 --- DBBroker.java 28 Jul 2004 18:54:54 -0000 1.39 *************** *** 458,462 **** /** * Store a document into the database. This method will save the document ! * metadata and add the document to the collection. * *@param doc --- 458,462 ---- /** * Store a document into the database. This method will save the document ! * metadata. * *@param doc *************** *** 464,467 **** --- 464,470 ---- public abstract void storeDocument(DocumentImpl doc); + public abstract void updateDocument(DocumentImpl doc) + throws LockException, PermissionDeniedException; + public abstract void storeBinaryResource(BinaryDocument blob, byte[] data); Index: BrokerPool.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/storage/BrokerPool.java,v retrieving revision 1.24 retrieving revision 1.25 diff -C2 -d -r1.24 -r1.25 *** BrokerPool.java 5 Jul 2004 20:02:46 -0000 1.24 --- BrokerPool.java 28 Jul 2004 18:54:54 -0000 1.25 *************** *** 250,253 **** --- 250,260 ---- } synchronized(this) { + // force the thread to wait until a pending sync has finished + while(syncRequired && threads.size() > 0) { + try { + this.wait(); + } catch(InterruptedException e) { + } + } if (pool.isEmpty()) { if (brokers < max) *************** *** 265,269 **** threads.put(Thread.currentThread(), broker); broker.incReferenceCount(); ! this.notifyAll(); return broker; } --- 272,276 ---- threads.put(Thread.currentThread(), broker); broker.incReferenceCount(); ! // this.notifyAll(); return broker; } *************** *** 341,345 **** threads.remove(Thread.currentThread()); pool.push(broker); ! if (syncRequired && pool.size() == brokers) { sync(broker); syncRequired = false; --- 348,352 ---- threads.remove(Thread.currentThread()); pool.push(broker); ! if (syncRequired && threads.size() == 0) { sync(broker); syncRequired = false; |