[hg] main-silver: #216228:org.apache.lucene.store.AlreadyClosedE...

  • From: Tomas Zezula < >
  • To:
  • Subject: [hg] main-silver: #216228:org.apache.lucene.store.AlreadyClosedE...
  • Date: Thu, 29 Nov 2012 03:31:40 -0800

changeset 8ff0103d54ff in main-silver ((none))
details: http://hg.netbeans.org/main-silver/rev/8ff0103d54ff
description:
        #216228:org.apache.lucene.store.AlreadyClosedException: this 
Directory is closed

diffstat:

 parsing.lucene/src/org/netbeans/modules/parsing/lucene/LuceneIndex.java      
        |  145 ++++++++-
 
parsing.lucene/test/unit/src/org/netbeans/modules/parsing/lucene/AsyncCloseTest.java
 |  160 ++++++++++
 2 files changed, 293 insertions(+), 12 deletions(-)

diffs (411 lines):

diff --git 
a/parsing.lucene/src/org/netbeans/modules/parsing/lucene/LuceneIndex.java 
b/parsing.lucene/src/org/netbeans/modules/parsing/lucene/LuceneIndex.java
--- a/parsing.lucene/src/org/netbeans/modules/parsing/lucene/LuceneIndex.java
+++ b/parsing.lucene/src/org/netbeans/modules/parsing/lucene/LuceneIndex.java
@@ -61,6 +61,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.ReadWriteLock;
@@ -383,7 +387,8 @@
             final Collection<S> toDelete, final Convertor<? super T, ? 
extends Document> docConvertor, 
             final Convertor<? super S, ? extends Query> queryConvertor) 
throws IOException {
         
-        final IndexWriter[] wr = new IndexWriter[1];
+        final IndexWriter wr = dirCache.acquireWriter();
+        try {
         try {
             if (LOGGER.isLoggable(Level.FINE)) {
                 LOGGER.log(Level.FINE, "Storing in TX {0}: {1} added, {2} 
deleted", 
@@ -395,9 +400,7 @@
             // nothing committed upon failure - readers not affected
             boolean ok = false;
             try {
-                if (wr[0] != null) {
-                    ((FlushIndexWriter)wr[0]).callFlush(false, true);
-                }
+                    ((FlushIndexWriter)wr).callFlush(false, true);
                 ok = true;
             } finally {
                 if (!ok) {
@@ -405,6 +408,9 @@
                 }
             }
         }
+        } finally {
+            dirCache.releaseWriter(wr);
+        }
     }
     
     private <S, T> void _doStore(
@@ -412,10 +418,8 @@
             @NonNull final Collection<S> toDelete,
             @NonNull final Convertor<? super T, ? extends Document> 
docConvertor, 
             @NonNull final Convertor<? super S, ? extends Query> 
queryConvertor,
-            @NonNull final IndexWriter[] ret) throws IOException {
-        final IndexWriter out = dirCache.acquireWriter();
+            @NonNull final IndexWriter out) throws IOException {
         try {
-            ret[0] = out;
             if (dirCache.exists()) {
                 for (S td : toDelete) {
                     out.deleteDocuments(queryConvertor.convert(td));
@@ -463,8 +467,6 @@
             throw Exceptions.attachMessage(e, "Lucene Index Folder: " + 
dirCache.folder.getAbsolutePath());
         } catch (IOException e) {
             throw Exceptions.attachMessage(e, "Lucene Index Folder: " + 
dirCache.folder.getAbsolutePath());
-        } finally {
-            dirCache.releaseWriter(out);
         }
     }
 
@@ -476,12 +478,21 @@
             final @NonNull Convertor<? super S, ? extends Query> 
queryConvertor,
             final boolean optimize) throws IOException {
         
-        IndexWriter[] wr = new IndexWriter[1];
+        final IndexWriter wr = dirCache.acquireWriter();
+        dirCache.storeCloseSynchronizer.enter();
+        try {
+            try {
         try {
             _doStore(data, toDelete, docConvertor, queryConvertor, wr);
         } finally {
             LOGGER.log(Level.FINE, "Committing {0}", this);
-            dirCache.close(wr[0]);
+                    dirCache.releaseWriter(wr);
+                }
+            } finally {
+                dirCache.close(wr);
+            }
+        } finally {
+            dirCache.storeCloseSynchronizer.exit();
         }
     }
         
@@ -566,6 +577,7 @@
         private final LockFactory lockFactory;
         private final CachePolicy cachePolicy;
         private final Analyzer analyzer;
+        private final StoreCloseSynchronizer storeCloseSynchronizer;
         private volatile FSDirectory fsDir;
         private RAMDirectory memDir;
         private CleanReference ref;
@@ -595,6 +607,7 @@
             this.fsDir = createFSDirectory(folder, lockFactory);
             this.cachePolicy = cachePolicy;                        
             this.analyzer = analyzer;
+            this.storeCloseSynchronizer = new StoreCloseSynchronizer();
         }
         
         Analyzer getAnalyzer() {
@@ -602,12 +615,26 @@
         }
         
         void clear() throws IOException {
+            Future<Void> sync;
+            while (true) {
             rwLock.writeLock().lock();
             try {
+                    sync = storeCloseSynchronizer.getSync();
+                    if (sync == null) {
                 doClear();
+                        break;
+                    }
             } finally {
                 rwLock.writeLock().unlock();
             }
+                try {
+                    sync.get();
+                } catch (InterruptedException ex) {
+                    break;
+                } catch (ExecutionException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
         }
                                 
         private synchronized void doClear() throws IOException {
@@ -688,12 +715,26 @@
         }
         
         void close (final boolean closeFSDir) throws IOException {
+            Future<Void> sync;
+            while (true) {
+                rwLock.writeLock().lock();
             try {
-                rwLock.writeLock().lock();
+                    sync = storeCloseSynchronizer.getSync();
+                    if (sync == null) {
                 doClose(closeFSDir);
+                        break;
+                    }
             } finally {
                 rwLock.writeLock().unlock();
             }                
+                try {
+                    sync.get();
+                } catch (InterruptedException ex) {
+                    break;
+                } catch (ExecutionException ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
         }
         
         synchronized void doClose (final boolean closeFSDir) throws 
IOException {
@@ -1193,4 +1234,84 @@
             super.flush(triggerMerges, true, flushDeletes);
         }
     }
+
+    private static final class StoreCloseSynchronizer {
+
+        private ThreadLocal<Boolean> isWriterThread = new 
ThreadLocal<Boolean>(){
+            @Override
+            protected Boolean initialValue() {
+                return Boolean.FALSE;
 }
+        };
+
+        //@GuardedBy("this")
+        private int depth;
+
+
+        StoreCloseSynchronizer() {}
+
+
+        synchronized void enter() {
+            depth++;
+            isWriterThread.set(Boolean.TRUE);
+        }
+
+        synchronized void exit() {
+            assert depth > 0;
+            depth--;
+            isWriterThread.remove();
+            if (depth == 0) {
+                notifyAll();
+            }
+        }
+
+        synchronized Future<Void> getSync() {
+            if (depth == 0 || isWriterThread.get() == Boolean.TRUE) {
+                return null;
+            } else {
+                return new Future<Void>() {
+                    @Override
+                    public boolean cancel(boolean mayInterruptIfRunning) {
+                        throw new UnsupportedOperationException();
+                    }
+
+                    @Override
+                    public boolean isCancelled() {
+                        return false;
+                    }
+
+                    @Override
+                    public boolean isDone() {
+                        synchronized(StoreCloseSynchronizer.this) {
+                            return depth == 0;
+                        }
+                    }
+
+                    @Override
+                    public Void get() throws InterruptedException, 
ExecutionException {
+                        synchronized (StoreCloseSynchronizer.this) {
+                            while (depth > 0) {
+                                StoreCloseSynchronizer.this.wait();
+                            }
+                        }
+                        return null;
+                    }
+
+                    @Override
+                    public Void get(long timeout, TimeUnit unit) throws 
InterruptedException, ExecutionException, TimeoutException {
+                        if (unit != TimeUnit.MILLISECONDS) {
+                            throw new UnsupportedOperationException();
+                        }
+                        synchronized (StoreCloseSynchronizer.this) {
+                            while (depth > 0) {
+                                StoreCloseSynchronizer.this.wait(timeout);
+                            }
+                        }
+                        return null;
+                    }
+                };
+            }
+        }
+
+    }
+}
diff --git 
a/parsing.lucene/test/unit/src/org/netbeans/modules/parsing/lucene/AsyncCloseTest.java
 
b/parsing.lucene/test/unit/src/org/netbeans/modules/parsing/lucene/AsyncCloseTest.java
new file mode 100644
--- /dev/null
+++ 
b/parsing.lucene/test/unit/src/org/netbeans/modules/parsing/lucene/AsyncCloseTest.java
@@ -0,0 +1,160 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2012 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.parsing.lucene;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.lucene.analysis.KeywordAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.parsing.lucene.support.Convertor;
+import org.netbeans.modules.parsing.lucene.support.Index;
+import org.netbeans.modules.parsing.lucene.support.IndexManager;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Parameters;
+
+/**
+ *
+ * @author Tomas Zezula
+ */
+public class AsyncCloseTest extends NbTestCase {
+
+    private static final String FLD_KEY = "key";    //NOI18N
+
+    private File indexFolder;
+
+
+    public AsyncCloseTest(final String name){
+        super(name);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        clearWorkDir();
+        indexFolder = FileUtil.normalizeFile(new 
File(getWorkDir(),"index"));   //NOI18N
+        indexFolder.mkdirs();
+    }
+
+
+
+    public void testAsyncClose() throws Exception {
+        final CountDownLatch slot = new CountDownLatch(1);
+        final CountDownLatch signal = new CountDownLatch(1);
+        final  CountDownLatch done = new CountDownLatch(1);
+        final AtomicReference<Exception> exception = new 
AtomicReference<Exception>();
+
+        final Index index = 
IndexManager.createTransactionalIndex(indexFolder, new KeywordAnalyzer());
+        final Thread worker = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    index.store(
+                       new ArrayList<String>(Arrays.asList("foo")), //NOI18N
+                       Collections.<String>emptySet(),
+                       new TestInsertConvertor(slot, signal),
+                       new TestDeleteConvertor(),
+                       true);
+                } catch (Exception ex) {
+                    exception.set(ex);
+                } finally {
+                    done.countDown();
+                }
+            }
+        });
+        worker.start();
+
+        signal.await();
+        slot.countDown();
+        index.close();
+        done.await();
+        assertNull(exception.get());
+    }
+
+    private static final class TestInsertConvertor implements 
Convertor<String, Document> {
+
+        private final CountDownLatch slot;
+        private final CountDownLatch signal;
+
+        TestInsertConvertor(
+                @NonNull final CountDownLatch slot,
+                @NonNull final CountDownLatch signal) {
+            Parameters.notNull("slot", slot);   //NOI18N
+            Parameters.notNull("signal", signal);   //NOI18N
+            this.slot = slot;
+            this.signal = signal;
+        }
+
+        @Override
+        public Document convert(String p) {
+            signal.countDown();
+
+            try {
+                this.slot.await();
+            } catch (InterruptedException ex) {
+                throw new RuntimeException(ex);
+            }
+
+            final Document doc = new Document();
+            doc.add(new Field(FLD_KEY, p, Field.Store.YES, 
Field.Index.ANALYZED_NO_NORMS));   //NOI18N
+            return doc;
+        }
+    }
+
+    private static final class TestDeleteConvertor implements 
Convertor<String, Query> {
+        @Override
+        public Query convert(String p) {
+            return new TermQuery(new Term(FLD_KEY,p));    //NOI18N
+        }
+    }
+
+}

[hg] main-silver: #216228:org.apache.lucene.store.AlreadyClosedE...

Tomas Zezula 11/29/2012

Project Features

About this Project

Editor was started in November 2009, is owned by Martin Ryzl, and has 147 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20131025.e7cbc9d). © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close