From: Wolfgang M. M. <wol...@us...> - 2004-07-05 20:02:56
|
Update of /cvsroot/exist/eXist-1.0/src/org/exist/storage In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25405/src/org/exist/storage Modified Files: BrokerPool.java DBBroker.java NativeBroker.java Log Message: Fixed concurrency issue in the dom.dbx node store: in some cases, a reading thread could interfere with a writing thread. As a result, some data pages got lost. Index: NativeBroker.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/storage/NativeBroker.java,v retrieving revision 1.86 retrieving revision 1.87 diff -C2 -d -r1.86 -r1.87 *** NativeBroker.java 2 Jul 2004 18:24:53 -0000 1.86 --- NativeBroker.java 5 Jul 2004 20:02:47 -0000 1.87 *************** *** 73,76 **** --- 73,77 ---- import org.exist.storage.store.DOMTransaction; import org.exist.storage.store.NodeIterator; + import org.exist.storage.store.StorageAddress; import org.exist.util.ByteArrayPool; import org.exist.util.ByteConversion; *************** *** 472,476 **** public Iterator getNodeIterator(NodeProxy proxy) { ! domDb.setOwnerObject(this); try { return new NodeIterator(this, domDb, proxy, false); --- 473,477 ---- public Iterator getNodeIterator(NodeProxy proxy) { ! // domDb.setOwnerObject(this); try { return new NodeIterator(this, domDb, proxy, false); *************** *** 938,960 **** lock.release(); } ! // now reindex the nodes ! Iterator iterator; ! if (node == null) { ! NodeList nodes = doc.getChildNodes(); ! NodeImpl n; ! for (int i = 0; i < nodes.getLength(); i++) { ! n = (NodeImpl) nodes.item(i); iterator = getNodeIterator( ! new NodeProxy(doc, n.getGID(), n.getInternalAddress())); iterator.next(); ! scanNodes(iterator, n, new NodePath(), false); } ! } else { ! iterator = ! getNodeIterator( ! new NodeProxy(doc, node.getGID(), node.getInternalAddress())); ! iterator.next(); ! scanNodes(iterator, node, node.getPath(), false); } elementIndex.reindex(oldDoc, node); --- 939,966 ---- lock.release(); } ! try { ! // now reindex the nodes ! Iterator iterator; ! if (node == null) { ! NodeList nodes = doc.getChildNodes(); ! NodeImpl n; ! for (int i = 0; i < nodes.getLength(); i++) { ! n = (NodeImpl) nodes.item(i); ! iterator = ! getNodeIterator( ! new NodeProxy(doc, n.getGID(), n.getInternalAddress())); ! iterator.next(); ! scanNodes(iterator, n, new NodePath(), false); ! } ! } else { iterator = getNodeIterator( ! new NodeProxy(doc, node.getGID(), node.getInternalAddress())); iterator.next(); ! scanNodes(iterator, node, node.getPath(), false); } ! } catch(Exception e) { ! LOG.error("Error occured while reindexing document: " + e.getMessage(), e); ! LOG.debug(domDb.debugPages(doc)); } elementIndex.reindex(oldDoc, node); *************** *** 1141,1144 **** --- 1147,1151 ---- newName = doc.getFileName().substring(p + 1); } + Lock lock = null; try { *************** *** 1150,1153 **** --- 1157,1162 ---- DocumentImpl oldDoc = destination.getDocument(this, newName); if(oldDoc != null) { + if(doc.getDocId() == oldDoc.getDocId()) + throw new PermissionDeniedException("Cannot copy resource to itself"); if(!destination.getPermissions().validate(user, Permission.UPDATE)) throw new PermissionDeniedException("Resource with same name exists in target " + *************** *** 1157,1165 **** "collection and update is denied"); collection.removeDocument(this, oldDoc.getFileName()); ! } else ! if(!destination.getPermissions().validate(user, Permission.WRITE)) throw new PermissionDeniedException("Insufficient privileges on target collection " + destination.getName()); ! DocumentImpl newDoc = new DocumentImpl(this, newName, destination); newDoc.copyOf(doc); --- 1166,1174 ---- "collection and update is denied"); collection.removeDocument(this, oldDoc.getFileName()); ! } else { ! if(!destination.getPermissions().validate(user, Permission.WRITE)) throw new PermissionDeniedException("Insufficient privileges on target collection " + destination.getName()); ! } DocumentImpl newDoc = new DocumentImpl(this, newName, destination); newDoc.copyOf(doc); *************** *** 1199,1204 **** final long start = System.currentTimeMillis(); try { final NodeImpl firstChild = (NodeImpl)doc.getFirstChild(); ! // dropping old structure index elementIndex.dropIndex(doc); --- 1208,1215 ---- final long start = System.currentTimeMillis(); try { + // checkTree(doc); final NodeImpl firstChild = (NodeImpl)doc.getFirstChild(); ! // LOG.debug(domDb.debugPages(doc)); ! // dropping old structure index elementIndex.dropIndex(doc); *************** *** 1211,1219 **** try { domDb.remove(idx, null); - domDb.flush(); } catch (BTreeException e) { LOG.warn("start() - " + "error while removing doc", e); - } catch (DBException e) { - LOG.warn("start() - " + "error while removing doc", e); } catch (IOException e) { LOG.warn("start() - " + "error while removing doc", e); --- 1222,1227 ---- *************** *** 1248,1252 **** new DOMTransaction(this, domDb) { public Object start() { - domDb.remove(doc.getAddress()); domDb.removeAll(firstChild.getInternalAddress()); return null; --- 1256,1259 ---- *************** *** 1255,1263 **** --- 1262,1274 ---- .run(); + // LOG.debug(domDb.debugPages(tempDoc)); + doc.copyChildren(tempDoc); doc.setSplitCount(0); doc.setAddress(-1); doc.setPageCount(tempDoc.getPageCount()); + // checkTree(doc); storeDocument(doc); + LOG.debug("new doc address = " + StorageAddress.toString(doc.getAddress())); closeDocument(); *************** *** 1310,1313 **** --- 1321,1365 ---- } + public void checkTree(DocumentImpl doc) { + LOG.debug("Checking DOM tree for document " + doc.getFileName()); + 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); + } + } + + private void checkTree(Iterator iterator, NodeImpl node) { + if (node.hasChildNodes()) { + final long firstChildId = XMLUtil.getFirstChildId((DocumentImpl)node.getOwnerDocument(), + node.getGID()); + if (firstChildId < 0) { + LOG.fatal( + "no child found: expected = " + + node.getChildCount() + + "; node = " + + node.getNodeName() + + "; gid = " + + node.getGID()); + throw new IllegalStateException("wrong node id"); + } + final long lastChildId = firstChildId + node.getChildCount(); + NodeImpl child; + for (long gid = firstChildId; gid < lastChildId; gid++) { + child = (NodeImpl) iterator.next(); + if(child == null) + LOG.debug("child " + gid + " not found for node: " + node.getNodeName() + + "; last = " + lastChildId + "; children = " + node.getChildCount()); + child.setGID(gid); + checkTree(iterator, child); + } + } + } + public String getNodeValue(final NodeProxy proxy) { return (String) new DOMTransaction(this, domDb, Lock.READ_LOCK) { *************** *** 1921,1924 **** --- 1973,1978 ---- DocumentImpl oldDoc = destination.getDocument(this, newName); if(oldDoc != null) { + if(doc.getDocId() == oldDoc.getDocId()) + throw new PermissionDeniedException("Cannot move resource to itself"); if(!destination.getPermissions().validate(user, Permission.UPDATE)) throw new PermissionDeniedException("Resource with same name exists in target " + *************** *** 1932,1946 **** throw new PermissionDeniedException("Insufficient privileges on target collection " + destination.getName()); collection.unlinkDocument(doc); ! elementIndex.dropIndex(doc); ! textEngine.dropIndex(doc); ! saveCollection(collection); ! doc.setFileName(newName); destination.addDocument(this, doc); doc.setCollection(destination); ! // reindexing ! reindex(doc); saveCollection(destination); } catch (TriggerException e) { --- 1986,2005 ---- throw new PermissionDeniedException("Insufficient privileges on target collection " + destination.getName()); + + boolean renameOnly = collection.getId() == destination.getId(); collection.unlinkDocument(doc); ! if(!renameOnly) { ! elementIndex.dropIndex(doc); ! textEngine.dropIndex(doc); ! saveCollection(collection); ! } doc.setFileName(newName); destination.addDocument(this, doc); doc.setCollection(destination); ! if(!renameOnly) { ! // reindexing ! reindex(doc); ! } saveCollection(destination); } catch (TriggerException e) { *************** *** 1953,1960 **** --- 2012,2065 ---- } + public void copyCollection(Collection collection, Collection destination, String newName) + throws PermissionDeniedException, LockException { + if (readOnly) + throw new PermissionDeniedException(DATABASE_IS_READ_ONLY); + if(!collection.getPermissions().validate(user, Permission.READ)) + throw new PermissionDeniedException("Read permission denied on collection " + + collection.getName()); + if(collection.getId() == destination.getId()) + throw new PermissionDeniedException("Cannot move collection to itself"); + if(!destination.getPermissions().validate(user, Permission.WRITE)) + throw new PermissionDeniedException("Insufficient privileges on target collection " + + destination.getName()); + if(newName == null) { + int p = collection.getName().lastIndexOf('/'); + newName = collection.getName().substring(p + 1); + } + if(newName.indexOf('/') > -1) + throw new PermissionDeniedException("New collection name is illegal (may not contain a '/')"); + Lock lock = null; + try { + lock = collectionsDb.getLock(); + lock.acquire(Lock.WRITE_LOCK); + newName = destination.getName() + '/' + newName; + // check if another collection with the same name exists at the destination + Collection old = getCollection(newName); + if(old != null) + removeCollection(old.getName()); + Collection destCollection = getOrCreateCollection(newName); + for(Iterator i = collection.iterator(this); i.hasNext(); ) { + DocumentImpl child = (DocumentImpl) i.next(); + + DocumentImpl newDoc = new DocumentImpl(this, child.getFileName(), destCollection); + newDoc.copyOf(child); + copyResource(child, newDoc); + flush(); + destCollection.addDocument(this, child); + } + saveCollection(destCollection); + saveCollection(destination); + } finally { + lock.release(); + } + } + public void moveCollection(Collection collection, Collection destination, String newName) throws PermissionDeniedException, LockException { if (readOnly) throw new PermissionDeniedException(DATABASE_IS_READ_ONLY); + if(collection.getId() == destination.getId()) + throw new PermissionDeniedException("Cannot move collection to itself"); if(collection.getName().equals(ROOT_COLLECTION)) throw new PermissionDeniedException("Cannot move the db root collection"); Index: DBBroker.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/storage/DBBroker.java,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** DBBroker.java 27 Jun 2004 21:10:07 -0000 1.36 --- DBBroker.java 5 Jul 2004 20:02:46 -0000 1.37 *************** *** 94,97 **** --- 94,99 ---- protected int docFragmentationLimit = 25; + protected String id; + /** * Save the global symbol table. The global symbol table stores *************** *** 175,179 **** xqueryService = new XQuery(this); } ! /** * Set the user that is currently using this DBBroker object. --- 177,181 ---- xqueryService = new XQuery(this); } ! /** * Set the user that is currently using this DBBroker object. *************** *** 486,489 **** --- 488,501 ---- /** + * Copy a collection to the destination collection and rename it. + * + * @param doc the resource to move + * @param destination the destination collection + * @param new Name the new name the resource should have in the destination collection + */ + public abstract void copyCollection(Collection collection, Collection destination, String newName) + throws PermissionDeniedException, LockException; + + /** * Copy a resource to the destination collection and rename it. * *************** *** 499,502 **** --- 511,523 ---- public abstract void defrag(DocumentImpl doc); + /** + * Perform a consistency check on the specified document. + * + * This checks if the DOM tree is consistent. + * + * @param doc + */ + public abstract void checkTree(DocumentImpl doc); + public void sync() { /* *************** *** 585,587 **** --- 606,620 ---- public abstract int getPageSize(); + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public String toString() { + return id; + } } Index: BrokerPool.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/storage/BrokerPool.java,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -d -r1.23 -r1.24 *** BrokerPool.java 4 Jun 2004 09:44:34 -0000 1.23 --- BrokerPool.java 5 Jul 2004 20:02:46 -0000 1.24 *************** *** 233,236 **** --- 233,237 ---- active.add(broker); brokers++; + broker.setId(broker.getClass().getName() + '_' + brokers); return broker; } |