logo       

svn commit: r530223 - in /xml/xindice/trunk/java: src/org/apache/xindice/co: msg#00028

Subject: svn commit: r530223 - in /xml/xindice/trunk/java: src/org/apache/xindice/core/ tests/src/org/apache/xindice/core/ tests/src/org/apache/xindice/core/filer/ tests/src/org/apache/xindice/core/indexer/
Author: vgritsenko
Date: Wed Apr 18 18:48:06 2007
New Revision: 530223

URL: http://svn.apache.org/viewvc?view=rev&rev=530223
Log:
applied patch from bug #42026

Modified:
    xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java
    xml/xindice/trunk/java/src/org/apache/xindice/core/CollectionManager.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/CollectionTest.java
    xml/xindice/trunk/java/tests/src/org/apache/xindice/core/DatabaseTest.java
    
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/filer/FilerTestBase.java
    
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/ValueIndexerTest.java

Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java
URL: 
http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java?view=diff&rev=530223&r1=530222&r2=530223
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java 
(original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java Wed Apr 
18 18:48:06 2007
@@ -59,8 +59,11 @@
 
 import java.io.File;
 import java.io.UnsupportedEncodingException;
+import java.lang.ref.WeakReference;
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Map;
+import java.util.WeakHashMap;
 
 /**
  * Collection represents a collection of Documents maintains links to
@@ -218,6 +221,9 @@
     private Collection parent;
     private SymbolTable symbols;
 
+    // document keys identity map
+    private final Map identityMap = new WeakHashMap();
+
 
     protected Collection() {
         documentId = System.currentTimeMillis();
@@ -602,39 +608,42 @@
             return null;
         }
 
-        if (null == getEntry(id)) {
-            throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
-                                  "Resource '" + id + "' does not exist in '" 
+ getCanonicalName() + "'");
-        }
-
-        MetaSystemCollection metacol = getMetaSystemCollection();
-        MetaData meta = metacol.getDocumentMeta(this, id);
+        Key key = getIdentityKey(createNewKey(id));
+        synchronized (key) {
+            if (null == getEntry(id)) {
+                throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
+                                      "Resource '" + id + "' does not exist in 
'" + getCanonicalName() + "'");
+            }
 
-        /*
-        FIXME It is more efficient to store (and retrieve) created/modified 
timestamps
-              from the Record itself instead of storing them in the separate 
MetaData
-              object. Storing in the Record avoids writing two documents on 
each update
-              (Document itself and its MetaData).
-              Retrieval of the timestamps from Record can be implemented via 
TimeRecord.
+            MetaSystemCollection metacol = getMetaSystemCollection();
+            MetaData meta = metacol.getDocumentMeta(this, id);
 
-        TimeRecord rec = null;
-        if( null == meta || !meta.hasContext() )
-           rec = getDatabase().getTime(path);
+            /*
+            FIXME It is more efficient to store (and retrieve) 
created/modified timestamps
+                  from the Record itself instead of storing them in the 
separate MetaData
+                  object. Storing in the Record avoids writing two documents 
on each update
+                  (Document itself and its MetaData).
+                  Retrieval of the timestamps from Record can be implemented 
via TimeRecord.
+
+            TimeRecord rec = null;
+            if( null == meta || !meta.hasContext() )
+               rec = getDatabase().getTime(path);
+
+            long created = (null != rec) ? rec.getCreatedTime() : 
System.currentTimeMillis();
+            long modified = (null != rec) ? rec.getModifiedTime() : 
System.currentTimeMillis();
+            */
 
-        long created = (null != rec) ? rec.getCreatedTime() : 
System.currentTimeMillis();
-        long modified = (null != rec) ? rec.getModifiedTime() : 
System.currentTimeMillis();
-        */
+            // this is wrong.. but it should work for now...
+            long now = System.currentTimeMillis();
+            if (null == meta) {
+                meta = new MetaData(MetaData.DOCUMENT, 
getCanonicalDocumentName(id), now, now);
+                metacol.setDocumentMeta(this, id, meta);
+            } else if (!meta.hasContext()) {
+                meta.setContext(now, now);
+            }
 
-        // this is wrong.. but it should work for now...
-        long now = System.currentTimeMillis();
-        if (null == meta) {
-            meta = new MetaData(MetaData.DOCUMENT, 
getCanonicalDocumentName(id), now, now);
-            metacol.setDocumentMeta(this, id, meta);
-        } else if (!meta.hasContext()) {
-            meta.setContext(now, now);
+            return meta;
         }
-
-        return meta;
     }
 
     /**
@@ -681,86 +690,88 @@
 
         checkFiler(FaultCodes.COL_NO_FILER);
 
-        Key key = createNewKey(docKey);
+        Key key = getIdentityKey(createNewKey(docKey));
+        synchronized (key) {
 
-        /*
-         * If the key has a corresponding value in the cache, return it
-         * and save a disk access.
-         *
-         * At some point the current document-centric cache implementation
-         * needs to be converted to an entry cache which can hold both
-         * Document and byte[].
-         */
-        if (documentCache != null) {
-            Document document = documentCache.getDocument(this, key);
-            if (document != null) {
-                if (log.isTraceEnabled()) {
-                    log.trace(localDebugHeader + "Returning cached: " + 
document);
-                }
+            /*
+             * If the key has a corresponding value in the cache, return it
+             * and save a disk access.
+             *
+             * At some point the current document-centric cache implementation
+             * needs to be converted to an entry cache which can hold both
+             * Document and byte[].
+             */
+            if (documentCache != null) {
+                Document document = documentCache.getDocument(this, key);
+                if (document != null) {
+                    if (log.isTraceEnabled()) {
+                        log.trace(localDebugHeader + "Returning cached: " + 
document);
+                    }
 
-                return document;
+                    return document;
+                }
             }
-        }
 
-        Record record = filer.readRecord(key);
-        if (record == null) {
-            return null;
-        }
-
-        Value value;
-        InlineMetaMap metaMap = null;
-        if (inlineMetaService == null) {
-            value = record.getValue();
-
-            if (log.isTraceEnabled()) {
-                log.trace(localDebugHeader + "Type is not available, Length=" 
+ value.getLength());
+            Record record = filer.readRecord(key);
+            if (record == null) {
+                return null;
             }
-        } else {
-            InlineMetaService.DatabaseEntry databaseEntry = 
inlineMetaService.readDatabaseEntry(record.getValue());
-            metaMap = databaseEntry.map;
-            value = databaseEntry.value;
 
-            if (log.isTraceEnabled()) {
-                log.trace(localDebugHeader + "Type=" + metaMap.get("type") + 
", Length=" + value.getLength());
-            }
-        }
+            Value value;
+            InlineMetaMap metaMap = null;
+            if (inlineMetaService == null) {
+                value = record.getValue();
 
-        if (inlineMetaService == null || 
metaMap.get("type").equals(ResourceTypeReader.XML)) {
-            Document document;
-            if (compressed) {
-                document = new DocumentImpl(value.getData(), symbols, new 
NodeSource(this, key));
-                flushSymbolTable();
                 if (log.isTraceEnabled()) {
-                    log.trace(localDebugHeader +
-                              "Compressed XML document=<" + 
TextWriter.toString(document) + ">");
-                }
-
-                if (documentCache != null) {
-                    documentCache.putDocument(this, key, value.getData());
+                    log.trace(localDebugHeader + "Type is not available, 
Length=" + value.getLength());
                 }
             } else {
-                String documentChars = value.toString();
+                InlineMetaService.DatabaseEntry databaseEntry = 
inlineMetaService.readDatabaseEntry(record.getValue());
+                metaMap = databaseEntry.map;
+                value = databaseEntry.value;
+
                 if (log.isTraceEnabled()) {
-                    log.trace(localDebugHeader + "Pre parseDocument(): 
value=<" + documentChars + ">");
+                    log.trace(localDebugHeader + "Type=" + metaMap.get("type") 
+ ", Length=" + value.getLength());
                 }
+            }
 
-                // FIXME These should be no reason here to re-compress the 
document & flush symbols table?
-                document = parseDocument(key, documentChars);
-                flushSymbolTable();
+            if (inlineMetaService == null || 
metaMap.get("type").equals(ResourceTypeReader.XML)) {
+                Document document;
+                if (compressed) {
+                    document = new DocumentImpl(value.getData(), symbols, new 
NodeSource(this, key));
+                    flushSymbolTable();
+                    if (log.isTraceEnabled()) {
+                        log.trace(localDebugHeader +
+                                  "Compressed XML document=<" + 
TextWriter.toString(document) + ">");
+                    }
 
-                if (documentCache != null) {
-                    documentCache.putDocument(this, key, documentChars);
+                    if (documentCache != null) {
+                        documentCache.putDocument(this, key, value.getData());
+                    }
+                } else {
+                    String documentChars = value.toString();
+                    if (log.isTraceEnabled()) {
+                        log.trace(localDebugHeader + "Pre parseDocument(): 
value=<" + documentChars + ">");
+                    }
+
+                    // FIXME These should be no reason here to re-compress the 
document & flush symbols table?
+                    document = parseDocument(key, documentChars);
+                    flushSymbolTable();
+
+                    if (documentCache != null) {
+                        documentCache.putDocument(this, key, documentChars);
+                    }
                 }
-            }
 
-            DBObserver.getInstance().loadDocument(this, record, document);
-            return document;
-        } else {
-            if (log.isTraceEnabled()) {
-                log.trace(localDebugHeader + "Binary document");
-            }
+                DBObserver.getInstance().loadDocument(this, record, document);
+                return document;
+            } else {
+                if (log.isTraceEnabled()) {
+                    log.trace(localDebugHeader + "Binary document");
+                }
 
-            return value.getData();
+                return value.getData();
+            }
         }
     }
 
@@ -1076,23 +1087,33 @@
      * It now does update non-inline metadata if the user has configured it.
      */
     private void putBinary(Key key, byte[] bytes, boolean create) throws 
DBException {
-        if (!create) {
-            byte[] storedBytes = getBinary(key);
-            if (storedBytes == null) {
-                // TODO: Do we need a COL_KEY_ALREADY_PRESENT fault so that 
the caller can interpret this exception?
-                throw new DBException(FaultCodes.COL_CANNOT_STORE,
-                                      "Error storing binary resource '" + key 
+ "' in '" + getCanonicalName() +
-                                      "': the 'create' flag is false and the 
key is already in database");
+        synchronized (getIdentityKey(key)) {
+            Object entry = getEntry(key);
+            if (!create) {
+                if (entry == null) {
+                    // TODO: Do we need a COL_KEY_ALREADY_PRESENT fault so 
that the caller can interpret this exception?
+                    throw new DBException(FaultCodes.COL_CANNOT_STORE,
+                                          "Error storing binary resource '" + 
key + "' in '" + getCanonicalName() +
+                                          "': the 'create' flag is false and 
the key is already in database");
+                }
             }
-        }
 
-        InlineMetaMap map = inlineMetaService.getEmptyMap();
-        map.put("type", ResourceTypeReader.BINARY);
-        Value value = inlineMetaService.createValue(map, bytes, 0, 
bytes.length);
-        filer.writeRecord(key, value);
+            if (entry != null && entry instanceof Document) {
+                // binary resources aren't stored in cache or indexes
+                if (documentCache != null) {
+                    documentCache.removeDocument(this, key);
+                }
+                indexManager.removeDocument(key, (Document) entry);
+            }
+
+            InlineMetaMap map = inlineMetaService.getEmptyMap();
+            map.put("type", ResourceTypeReader.BINARY);
+            Value value = inlineMetaService.createValue(map, bytes, 0, 
bytes.length);
+            filer.writeRecord(key, value);
 
-        // update the meta for this document
-        updateDocumentMeta(key.toString());
+            // update the meta for this document
+            updateDocumentMeta(key.toString());
+        }
     }
 
     /**
@@ -1132,6 +1153,7 @@
         byte[] documentBytes;
         String documentChars = null;
 
+        // FIXME: concurrent symbol table access.
         if (compressed) {
             // Create compressed document bytes to be stored in the filer
             documentBytes = DOMCompressor.compress(document, symbols);
@@ -1174,35 +1196,40 @@
         // Symbol table could have been updated above, flush it to the disk.
         flushSymbolTable();
 
-        // Temporary until insert and update are separate
-        Document oldDoc = getDocument(key);
-        if (oldDoc != null) {
-            indexManager.removeDocument(key, oldDoc);
-        }
-        indexManager.addDocument(key, document);
-
-        // Construct the Value object that is stored in the BTree.
-        Value value;
-        if (inlineMetaService == null) {
-            value = new Value(documentBytes);
-        } else {
-            InlineMetaMap map = inlineMetaService.getEmptyMap();
-            map.put("type", ResourceTypeReader.XML);
-            value = inlineMetaService.createValue(map, documentBytes, 0, 
documentBytes.length);
-        }
-        filer.writeRecord(key, value);
-
-        // Cache Stuff
-        if (documentCache != null) {
-            if (compressed) {
-                documentCache.putDocument(this, key, documentBytes);
+        key = getIdentityKey(key);
+        Object oldDoc;
+        synchronized (key) {
+            // Temporary until insert and update are separate
+            oldDoc = getEntry(key);
+            if (oldDoc != null && oldDoc instanceof Document) {
+                indexManager.removeDocument(key, (Document) oldDoc);
+            }
+            indexManager.addDocument(key, document);
+
+            // Construct the Value object that is stored in the BTree.
+            Value value;
+            if (inlineMetaService == null) {
+                value = new Value(documentBytes);
             } else {
-                documentCache.putDocument(this, key, documentChars);
+                InlineMetaMap map = inlineMetaService.getEmptyMap();
+                map.put("type", ResourceTypeReader.XML);
+                value = inlineMetaService.createValue(map, documentBytes, 0, 
documentBytes.length);
+            }
+            filer.writeRecord(key, value);
+
+            // Cache Stuff
+            if (documentCache != null) {
+                if (compressed) {
+                    documentCache.putDocument(this, key, documentBytes);
+                } else {
+                    documentCache.putDocument(this, key, documentChars);
+                }
             }
+
+            // Update the meta for this document
+            updateDocumentMeta(key.toString());
         }
 
-        // Update the meta for this document
-        updateDocumentMeta(key.toString());
         DBObserver.getInstance().putDocument(this, key, document, oldDoc == 
null);
     }
 
@@ -1279,25 +1306,28 @@
 
         Key objKey = createNewKey(key);
 
-        Object oldDoc = getEntry(objKey);
-        if (oldDoc != null && oldDoc instanceof Document) {
-            indexManager.removeDocument(objKey, (Document)oldDoc);
-        }
+        objKey = getIdentityKey(objKey);
+        synchronized (objKey) {
+            Object oldDoc = getEntry(objKey);
+            if (oldDoc != null && oldDoc instanceof Document) {
+                indexManager.removeDocument(objKey, (Document)oldDoc);
+            }
 
-        if (documentCache != null) {
-            documentCache.removeDocument(this, objKey);
-        }
+            if (documentCache != null) {
+                documentCache.removeDocument(this, objKey);
+            }
 
-        if (!filer.deleteRecord(objKey)) {
-            throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
-                                  "Resource '" + objKey + "' does not exist in 
'" + getCanonicalName() + "'");
-        }
+            if (!filer.deleteRecord(objKey)) {
+                throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
+                                      "Resource '" + objKey + "' does not 
exist in '" + getCanonicalName() + "'");
+            }
 
-        // update the meta for this collection if necessary
-        updateCollectionMeta();
-        // remove the document meta
-        if (isMetaEnabled()) {
-            getMetaSystemCollection().dropDocumentMeta(this, 
objKey.toString());
+            // update the meta for this collection if necessary
+            updateCollectionMeta();
+            // remove the document meta
+            if (isMetaEnabled()) {
+                getMetaSystemCollection().dropDocumentMeta(this, 
objKey.toString());
+            }
         }
         DBObserver.getInstance().dropDocument(this, objKey);
     }
@@ -1478,7 +1508,7 @@
         if (log.isInfoEnabled()) {
             log.info(debugHeader() + "Set document " + docKey);
         }
-        putDocument(createNewKey(docKey), document /*, false */);
+        putDocument(createNewKey(docKey), document);
     }
 
     /**
@@ -1495,25 +1525,28 @@
             return;
         }
 
-        Object obj = getEntry(id);
-        if (null == obj) {
-            throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
-                                  "Resource '" + id + "' does not exist in '" 
+ getCanonicalName() + "'");
-        }
-
-        if (null != meta) {
-            if (meta.getType() == MetaData.UNKNOWN || meta.getType() == 
MetaData.COLLECTION) {
-                throw new DBException(FaultCodes.GEN_UNKNOWN,
-                                      "Mismatch type of meta data for document 
" + getCanonicalDocumentName(id));
+        Key key = getIdentityKey(createNewKey(id));
+        synchronized (key) {
+            Object obj = getEntry(id);
+            if (null == obj) {
+                throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
+                                      "Resource '" + id + "' does not exist in 
'" + getCanonicalName() + "'");
             }
 
-            if (log.isInfoEnabled()) {
-                log.info(debugHeader() + "Set document meta " + id);
+            if (null != meta) {
+                if (meta.getType() == MetaData.UNKNOWN || meta.getType() == 
MetaData.COLLECTION) {
+                    throw new DBException(FaultCodes.GEN_UNKNOWN,
+                                          "Mismatch type of meta data for 
document " + getCanonicalDocumentName(id));
+                }
+
+                if (log.isInfoEnabled()) {
+                    log.info(debugHeader() + "Set document meta " + id);
+                }
+                MetaSystemCollection metacol = getMetaSystemCollection();
+                MetaData current = metacol.getDocumentMeta(this, id);
+                current.copyDataFrom(meta);
+                metacol.setDocumentMeta(this, id, current);
             }
-            MetaSystemCollection metacol = getMetaSystemCollection();
-            MetaData current = metacol.getDocumentMeta(this, id);
-            current.copyDataFrom(meta);
-            metacol.setDocumentMeta(this, id, current);
         }
     }
 
@@ -1623,5 +1656,21 @@
             meta.setContext(0, now);
         }
         metacol.setDocumentMeta(this, id, meta);
+    }
+
+    private Key getIdentityKey(Key key) {
+        synchronized (identityMap) {
+            Key id = null;
+            WeakReference ref = (WeakReference) identityMap.get(key);
+            if (ref != null) {
+                id = (Key) ref.get();
+            }
+            if (id == null) {
+                id = key;
+                identityMap.put(id, new WeakReference(id));
+            }
+
+            return id;
+        }
     }
 }

Modified: 
xml/xindice/trunk/java/src/org/apache/xindice/core/CollectionManager.java
URL: 
http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/CollectionManager.java?view=diff&rev=530223&r1=530222&r2=530223
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/CollectionManager.java 
(original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/CollectionManager.java 
Wed Apr 18 18:48:06 2007
@@ -26,10 +26,11 @@
 import org.apache.xindice.util.ConfigurationCallback;
 import org.apache.xindice.util.XindiceException;
 
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.StringTokenizer;
-import java.util.Iterator;
 
 /**
  * CollectionManager is the base class for both Database and Collection.
@@ -45,8 +46,7 @@
     private static final String[] EMPTY_STRINGS = new String[0];
     private static final String NAME = "name";
 
-    // FIXME: Access to collections and config is not synchronized
-    private final Map collections = new HashMap();
+    private final Map collections = Collections.synchronizedMap(new HashMap());
     private Configuration config;
 
 
@@ -83,6 +83,10 @@
             throw new DBException(FaultCodes.COL_CANNOT_CREATE,
                                   "Null or empty collection name");
         }
+        if (cfg == null) {
+            throw new DBException(FaultCodes.COL_CANNOT_CREATE,
+                                  "Error creating collection '" + path + "': 
null config");
+        }
 
         if (path.indexOf("/") != -1) {
             CollectionManager cm = this;
@@ -109,50 +113,56 @@
         }
 
         Collection collection = new Collection((Collection) this);
-        try {
-            // Do a name check to see if all is well
-            String n = cfg.getAttribute(NAME);
-            if (n == null || n.trim().equals("")) {
-                throw new DBException(FaultCodes.COL_CANNOT_CREATE,
-                                      "No name specified in collection 
configuration");
-            }
-            if (!n.equals(path)) {
-                throw new DBException(FaultCodes.COL_CANNOT_CREATE,
-                                      "Name does not match with path name");
-            }
+        String n = cfg.getAttribute(NAME);
 
-            if (getCollection(n) != null) {
-                throw new DBException(FaultCodes.COL_DUPLICATE_COLLECTION,
-                                      "Duplicate Collection '" + n + "'");
-            }
+        // Do a name check to see if all is well
+        if (n == null || n.trim().equals("")) {
+            throw new DBException(FaultCodes.COL_CANNOT_CREATE,
+                                  "No name specified in collection 
configuration");
+        }
+
+        if (!n.equals(path)) {
+            throw new DBException(FaultCodes.COL_CANNOT_CREATE,
+                                  "Name does not match with path name");
+        }
 
-            Configuration colConfig = this.config.getChild(COLLECTIONS, true);
-            colConfig.add(cfg);
+        synchronized(collections) {
+            try {
+                if (getCollection(n) != null) {
+                    throw new DBException(FaultCodes.COL_DUPLICATE_COLLECTION,
+                                          "Duplicate Collection '" + n + "'");
+                }
 
-            collection.setConfig(cfg);
-            collection.create();
-            collections.put(n, collection);
-            if (log.isInfoEnabled()) {
-                log.info("Created a new collection named '" + n + "'");
+                Configuration colConfig = this.config.getChild(COLLECTIONS, 
true);
+                colConfig.add(cfg);
+
+                collection.setConfig(cfg);
+                collection.create();
+                collections.put(n, collection);
+                if (log.isInfoEnabled()) {
+                    log.info("Created a new collection named '" + n + "'");
+                }
+            } catch (DBException e) {
+                // Do not wrap DBException
+                throw e;
+            } catch (Exception e) {
+                throw new DBException(FaultCodes.COL_CANNOT_CREATE,
+                                      "Error Creating Collection '" + path + 
"'", e);
             }
-        } catch (DBException e) {
-            // Do not wrap DBException
-            throw e;
-        } catch (Exception e) {
-            throw new DBException(FaultCodes.COL_CANNOT_CREATE,
-                                  "Error Creating Collection '" + path + "'", 
e);
+            return collection;
         }
-        return collection;
     }
 
     public boolean close() throws DBException {
-        for(Iterator i = collections.values().iterator(); i.hasNext(); ) {
-            Collection collection = (Collection)i.next();
-            try {
-                collection.close();
-            } catch (DBException e) {
-                if (log.isWarnEnabled()) {
-                    log.warn("ignored exception", e);
+        synchronized (collections) {
+            for(Iterator i = collections.values().iterator(); i.hasNext(); ) {
+                Collection collection = (Collection)i.next();
+                try {
+                    collection.close();
+                } catch (DBException e) {
+                    if (log.isWarnEnabled()) {
+                        log.warn("ignored exception", e);
+                    }
                 }
             }
         }
@@ -181,8 +191,11 @@
 
         if (cm != this) {
             return cm.dropCollection(collection);
-        } else {
-            final String name = collection.getName();
+        }
+
+        final String name = collection.getName();
+
+        synchronized (collections) {
             boolean dropped = collection.drop();
             if (dropped) {
                 collections.remove(name);
@@ -201,6 +214,7 @@
                     }
                 });
             }
+
             return dropped;
         }
     }

Modified: 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/CollectionTest.java
URL: 
http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/CollectionTest.java?view=diff&rev=530223&r1=530222&r2=530223
==============================================================================
--- 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/CollectionTest.java 
(original)
+++ 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/CollectionTest.java 
Wed Apr 18 18:48:06 2007
@@ -22,6 +22,7 @@
 import org.apache.xindice.core.data.NodeSet;
 import org.apache.xindice.core.query.XPathQueryResolver;
 import org.apache.xindice.util.Configuration;
+import org.apache.xindice.util.XindiceException;
 import org.apache.xindice.xml.TextWriter;
 import org.apache.xindice.xml.SymbolTable;
 import org.apache.xindice.xml.dom.DOMParser;
@@ -149,6 +150,68 @@
         String expected = TextWriter.toString(document);
         String actual   = TextWriter.toString(res);
         assertEquals("Documents do not match", expected, actual);
+    }
+
+    public void testConcurrentCreateCollection() throws Exception {
+        final String name = "create";
+
+        try {
+            final int THREADS = 10;
+            Thread[] threads = new Thread[THREADS];
+            final Counter count = new Counter();
+
+            for (int i = 0; i < THREADS; i++) {
+
+                threads[i] = new Thread() {
+                    public void run() {
+                        try {
+                            db.createCollection(name, new Configuration(
+                                    DOMParser.toDocument(
+                                            "<collection  compressed='true' 
name='" + name + "' inline-metadata='true'>" +
+                                            "  <filer 
class='org.apache.xindice.core.filer.BTreeFiler' />" +
+                                            "</collection>"), false
+                            ));
+                        } catch (DBException e) {
+                            if (e.faultCode == 
FaultCodes.COL_DUPLICATE_COLLECTION) {
+                                count.incCount();
+                            } else {
+                                throw new RuntimeException(e);
+                            }
+                        } catch (XindiceException e) {
+                            // ignore
+                        }
+                    }
+                };
+            }
+
+            for (int i = 0; i < THREADS; i++) {
+                threads[i].start();
+            }
+
+            for (int i = 0; i < THREADS; i++) {
+                threads[i].join();
+            }
+
+            assertEquals(THREADS - 1, count.getCount());
+
+        } finally {
+            Collection col = db.getCollection(name);
+                if (col != null) {
+                    db.dropCollection(col);
+                }
+        }
+    }
+
+    private class Counter {
+        int count;
+
+        public int getCount() {
+            return count;
+        }
+
+        public synchronized void incCount() {
+            count++;
+        }
     }
 
 // FIXME Define semantics of document cache, and write tests for it

Modified: 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/DatabaseTest.java
URL: 
http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/DatabaseTest.java?view=diff&rev=530223&r1=530222&r2=530223
==============================================================================
--- xml/xindice/trunk/java/tests/src/org/apache/xindice/core/DatabaseTest.java 
(original)
+++ xml/xindice/trunk/java/tests/src/org/apache/xindice/core/DatabaseTest.java 
Wed Apr 18 18:48:06 2007
@@ -34,29 +34,29 @@
 public class DatabaseTest extends TestCase {
 
     public static final String DATABASE =
-        "<root-collection dbroot=\"db/\" name=\"db\">" +
+        "<root-collection dbroot='db/' name='db' use-metadata='on'>" +
             "<queryengine>" +
-                "<resolver autoindex=\"false\" 
class=\"org.apache.xindice.core.query.XPathQueryResolver\" />" +
-                "<resolver 
class=\"org.apache.xindice.core.xupdate.XUpdateQueryResolver\" />" +
+                "<resolver autoindex='false' 
class='org.apache.xindice.core.query.XPathQueryResolver'/>" +
+                "<resolver 
class='org.apache.xindice.core.xupdate.XUpdateQueryResolver'/>" +
             "</queryengine>" +
         "</root-collection>";
 
     public static final String COLLECTIONA =
-        "<collection compressed=\"true\" name=\"CollectionA\">" +
-            "<filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" +
-            "<indexes />" +
+        "<collection compressed='true' name='CollectionA'>" +
+            "<filer class='org.apache.xindice.core.filer.BTreeFiler'/>" +
+            "<indexes/>" +
         "</collection>";
 
     public static final String COLLECTIONB =
-        "<collection compressed=\"true\" name=\"CollectionB\">" +
-            "<filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" +
-            "<indexes />" +
+        "<collection compressed='true' name='CollectionB'>" +
+            "<filer class='org.apache.xindice.core.filer.BTreeFiler'/>" +
+            "<indexes/>" +
         "</collection>";
 
     public static final String COLLECTIONC =
-        "<collection compressed=\"true\" name=\"CollectionC\" 
inline-metadata=\"true\">" +
-            "<filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" +
-            "<indexes />" +
+        "<collection compressed='true' name='CollectionC' 
inline-metadata='true'>" +
+            "<filer class='org.apache.xindice.core.filer.BTreeFiler'/>" +
+            "<indexes/>" +
         "</collection>";
 
        private Database db;

Modified: 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/filer/FilerTestBase.java
URL: 
http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/filer/FilerTestBase.java?view=diff&rev=530223&r1=530222&r2=530223
==============================================================================
--- 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/filer/FilerTestBase.java
 (original)
+++ 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/filer/FilerTestBase.java
 Wed Apr 18 18:48:06 2007
@@ -348,6 +348,54 @@
         }
     }
 
+   public void testConcurrentSameInsert() throws Exception {
+       assertTrue(filer.getRecordCount() == 0);
+
+       final int THREADS = 10;
+       final int ITERATIONS = 5;
+
+       Thread[] threads = new Thread[THREADS];
+       for (int i = 0; i < THREADS; i++) {
+           threads[i] = new Thread() {
+               public void run() {
+                   for (int ii = 0; ii < ITERATIONS; ii++) {
+                       Key key = new Key("key");
+                       Value value = new Value("<test document/>");
+                       try {
+                           filer.writeRecord(key, value);
+                       } catch (Exception e) {
+                           e.printStackTrace();
+                       }
+                   }
+               }
+           };
+           threads[i].setName("FilerTest" + i);
+       }
+
+       // Start all the threads at once
+       for (int i = 0; i < THREADS; i++) {
+           threads[i].start();
+       }
+       Thread.sleep(100);
+
+       for (int i = 0; i < THREADS; i++) {
+           threads[i].join();
+       }
+
+       filer.flush();
+
+       // Check results
+       assertEquals(1, filer.getRecordCount());
+       Key key = new Key("key");
+       Value value = new Value("<test document/>");
+       Record record = filer.readRecord(key);
+       assertNotNull("Record with key '" + key + "' was not found", record);
+       assertEquals("Expected record with key '" + key + "', found record with 
key '" + record.getKey() + "'",
+                    key, record.getKey());
+       assertEquals("Expected record with value '" + value + "', found record 
with value '" + record.getValue() + "'",
+                    value, record.getValue());
+   }
+    
     public void testLargeKey() throws Exception {
         assertTrue(filer.getRecordCount() == 0);
 

Modified: 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/ValueIndexerTest.java
URL: 
http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/ValueIndexerTest.java?view=diff&rev=530223&r1=530222&r2=530223
==============================================================================
--- 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/ValueIndexerTest.java
 (original)
+++ 
xml/xindice/trunk/java/tests/src/org/apache/xindice/core/indexer/ValueIndexerTest.java
 Wed Apr 18 18:48:06 2007
@@ -191,4 +191,32 @@
 
         assertEquals(1, match.length);
     }
+
+    public void testMixedValues() throws Exception {
+        Indexer ind = createIndex("MixIndex", "test@value", "string");
+
+        byte[] value = "<test value='1'/>".getBytes();
+
+        collection.insertBinary("key1", value);
+
+        Document document = DOMParser.toDocument("<test value='1'/>");
+        collection.insertDocument("key1", document);
+
+        IndexMatch[] match = query(ind, "test@value", "1", IndexQuery.EQ);
+        assertEquals("XML document did not get indexed: ", 1, match.length);
+
+        collection.insertBinary("key1", value);
+
+        match = query(ind, "test@value", "1", IndexQuery.EQ);
+        assertEquals("Found previous XML document in the index: ", 0, 
match.length);
+
+        document = DOMParser.toDocument("<test value='2'/>");
+        collection.insertDocument("key1", document);
+
+        match = query(ind, "test@value", "1", IndexQuery.EQ);
+        assertEquals("Found previous XML document in the index: ", 0, 
match.length);
+
+        match = query(ind, "test@value", "2", IndexQuery.EQ);
+        assertEquals("Did not find new XML document in the index: ", 1, 
match.length);
+    }
 }





<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

Recently Viewed:
audio.irate.dev...    yellowdog.gener...    ietf.ips/2002-0...    xfree86.fonts/2...    busybox/2003-07...    emacs.jdee/2004...    linux.mandrake....    hardware.microc...    user-groups.lin...    science.analysi...    version-control...    db.filemaker.de...    cluster.openmos...    mail.eyebrowse....    text.xml.xerces...    kde.devel.kwrit...    finance.moneyda...    gcc.regression/...    network.routing...    os.freebsd.deve...    recreation.radi...    qnx.openqnx.dev...    python.xml/2002...   
Home | blog view | USPTO Patent Archive | advertise | OSDir is an inevitable website. super tiny logo

Free Magazines

Cisco News
Receive a free quarterly e-newsletter with exclusive articles on how Cisco IT uses its own products and solutions to enable the business.
subscribe

Systems Management News, the newspaper for IT systems administration and data center managers! Each issue of Systems Management News is chock-full of news and analysis to help you understand what's happening in your field.
subscribe

The Enterprise Newsweekly eWeek is the essential technology information source for builders of e-business.
subscribe

Oracle Magazine Oracle Magazine contains technology strategy articles, sample code, tips, Oracle and partner news, how to articles for developers and DBAs, and more. Oracle (NASDAQ: ORCL) is the world's largest enterprise software company.
subscribe

Total Telecom Total Telecom is "The Economist of the communications industry".
subscribe