From d13def5f21a95b199ff3f43111e1bbf258bfebf7 Mon Sep 17 00:00:00 2001 From: "Chris M. Hostetter" Date: Fri, 30 Jun 2006 19:31:32 +0000 Subject: [PATCH] patch_29_06_06.diff from LUCENE-620 git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@418363 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucenestorage/ModifiedEntryFilter.java | 19 +- .../storage/lucenestorage/StorageBuffer.java | 555 +++++++++--------- .../lucenestorage/StorageCoreController.java | 86 ++- .../lucenestorage/StorageModifier.java | 20 +- .../lucene/gdata/utils/DateFormater.java | 4 +- .../TestModifiedEntryFilter.java | 4 +- .../lucenestorage/TestStorageModifier.java | 15 +- .../lucene/gdata/utils/TestDateFormater.java | 11 +- 8 files changed, 400 insertions(+), 314 deletions(-) diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.java index c7ee9f47996..0e06120738d 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/ModifiedEntryFilter.java @@ -16,14 +16,13 @@ package org.apache.lucene.gdata.storage.lucenestorage; -import java.io.IOException; -import java.util.BitSet; -import java.util.List; - -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermDocs; -import org.apache.lucene.search.Filter; +import java.io.IOException; +import java.util.BitSet; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.index.TermDocs; +import org.apache.lucene.search.Filter; /** * The {@link ModifiedEntryFilter} filters the given entryIds from the lucene @@ -42,14 +41,14 @@ public class ModifiedEntryFilter extends Filter { */ private static final long serialVersionUID = -1551686287704213591L; - private final List entyIds; + private final String[] entyIds; /** * Creates a new {@link ModifiedEntryFilter} * @param entryIds the entry id's to filter * */ - public ModifiedEntryFilter(List entryIds) { + public ModifiedEntryFilter(final String[] entryIds) { super(); this.entyIds = entryIds; } diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java index 22370d854f0..0721f72d156 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageBuffer.java @@ -12,10 +12,10 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -package org.apache.lucene.gdata.storage.lucenestorage; - + */ + +package org.apache.lucene.gdata.storage.lucenestorage; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -36,277 +36,280 @@ import org.apache.lucene.gdata.storage.lucenestorage.StorageEntryWrapper.Storage import com.google.gdata.data.BaseEntry; import com.google.gdata.data.ExtensionProfile; import com.google.gdata.data.Link; - -/** - * The StorageBuffer is used to buffer incoming updates, deletes and inserts to - * the storage. The storage uses an lucene index to store the enries. As - * modifying the index all the time an altering request comes in is not - * efficent. The entries will be added to the buffer to be available for - * incoming storage queries. If the loadfactor for the - * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier} is - * reached the modifier will perform a batch update on the index. Each entry - * will be associated with a feed id inside a associative datastructure to - * return a requested entry efficiently. - *

- * This implementation uses {@link java.util.concurrent.locks.ReadWriteLock}. - * The read lock may be held simultaneously by multiple reader threads, so long - * as there are no writers. The write lock is exclusive.

- * - * @see java.util.concurrent.locks.ReentrantReadWriteLock - * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier - * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController - * - * @author Simon Willnauer - * - */ -public class StorageBuffer { - private static final Log LOG = LogFactory.getLog(StorageBuffer.class); - - private final Map> bufferMap; - - private final Map modifiyMap; - - private final List excludeList; - - private final ReadWriteLock lock = new ReentrantReadWriteLock(true); - - private final Lock readLock = this.lock.readLock(); - - private final Lock writeLock = this.lock.writeLock(); - - private final static int DEFAULT_BUFFER_COUNT = 10; - - /** - * Constructs a new StorageBuffer. - *

- * The expectedBufferCount sould be higher than the maximum of entries added - * to the buffer, resizing the buffer is very efficient. For detailed - * infomation {@link HashMap} as this is used inside the buffer - *

- * - * @param expectedBufferCount - - * the expected size of the buffer - * - */ - protected StorageBuffer(final int expectedBufferCount) { - this.bufferMap = new HashMap>( - expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT - : expectedBufferCount); - this.excludeList = new ArrayList( - expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT - : expectedBufferCount); - this.modifiyMap = new HashMap( - expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT - : expectedBufferCount); - } - - /** - * Adds a {@link StorageEntryWrapper} to the buffer. If a wrapper - * representing the same entry are already in the buffer the wrapper will be - * replaced. - * - * @param wrapper - - * the wrapper to buffer - */ - public void addEntry(final StorageEntryWrapper wrapper) { - this.writeLock.lock(); - try { - if (LOG.isInfoEnabled()) - LOG.info(" Buffering wrapper - " + wrapper.getOperation() - + " ID: " + wrapper.getEntryId() + " FeedID: " - + wrapper.getFeedId()); - if (wrapper.getOperation().equals(StorageOperation.DELETE)) - return; - - String feedId = wrapper.getFeedId(); - if (this.bufferMap.containsKey(feedId)) - this.bufferMap.get(feedId).put(wrapper.getEntryId(), wrapper); - else { - Map newFeedMap = new HashMap( - 20); - newFeedMap.put(wrapper.getEntryId(), wrapper); - this.bufferMap.put(feedId, newFeedMap); - - } - addLastModified(wrapper.getFeedId(),wrapper.getTimestamp()); - } finally { - /* - * add all to exclude from searches doc will be available via the - * buffer - */ - this.excludeList.add(wrapper.getEntryId()); - this.writeLock.unlock(); - } - } - - private void addLastModified(final String feedId,Long timestamp){ - if(this.modifiyMap.containsKey(feedId)) - this.modifiyMap.remove(feedId); - this.modifiyMap.put(feedId,timestamp); - - } - - protected Long getFeedLastModified(final String feedId){ - return this.modifiyMap.get(feedId); - } - protected Set> getLastModified(){ - return this.modifiyMap.entrySet(); - } - - - - /** - * Returns all entries for the given feed id sorted by the update timestamp - * desc. - * - * @param feedId - - * the feed id - * @return a {@link List} of all {@link StorageEntryWrapper} object buffered - * in this buffer or an empty list if not entry has been buffered - * for the given feed - */ - public List getSortedEntries(String feedId) { - this.readLock.lock(); - try { - if (!this.bufferMap.containsKey(feedId)) - return null; - Map tempMap = this.bufferMap - .get(feedId); - if (tempMap == null) - return null; - Collection col = tempMap.values(); - List returnList = new ArrayList( - col); - Collections.sort(returnList); - return returnList; - - } finally { - this.readLock.unlock(); - } - - } - - /** - * Adds a deleted entry to the buffer. - * - * @param entryId - - * the deleted entry id - * @param feedId - - * the feed of the entry - */ - public void addDeleted(final String entryId, final String feedId) { - this.writeLock.lock(); - try { - this.excludeList.add(entryId); - Map tempMap = this.bufferMap - .get(feedId); - if (tempMap == null) - return; - tempMap.remove(entryId); - this.addLastModified(feedId,new Long(System.currentTimeMillis())); - } finally { - this.writeLock.unlock(); - - } - - } - - /** - * Returns an entry for the given entry id in the feed context spezified by - * the feed id; - * - * @param entryId - - * the id of the entry to return - * @param feedId - - * the feed containing the entry - * @return - the entry or null if the corresponding entry is - * not in the buffer. - */ - public StorageEntryWrapper getEntry(final String entryId, - final String feedId) { - this.readLock.lock(); - try { - - if (this.bufferMap.containsKey(feedId)) - return this.bufferMap.get(feedId).get(entryId); - return null; - - } finally { - this.readLock.unlock(); - } - } - - /** - * The buffer contains updated and delete entries. These entries are already - * available in the lucene index but should not be found during search. - * - *

- * this list contains all entries should not be found by the index searcher - *

- * - * @see ModifiedEntryFilter - * @return - a {@link List} of entries to be omitted from a lucene index - * search - */ - public List getExculdList() { - this.readLock.lock(); - try { - return this.excludeList; - } finally { - this.readLock.unlock(); - } - } - - // not synchronized - private void clearBuffer() { - this.bufferMap.clear(); - this.excludeList.clear(); - this.modifiyMap.clear(); - - } - - /** - * clears the buffer - - */ - public void close() { - this.writeLock.lock(); - try { - clearBuffer(); - } finally { - this.writeLock.unlock(); - } - - } - - - static class BufferableEntry extends BaseEntry{ - - /** - * - */ - @SuppressWarnings("unchecked") - public BufferableEntry() { - super(); - this.links = new LinkedList(); - } - /** - * @param arg0 - */ - @SuppressWarnings("unchecked") - public BufferableEntry(BaseEntry arg0) { - super(arg0); - this.links = new LinkedList(); - } +/** + * The StorageBuffer is used to buffer incoming updates, deletes and inserts to + * the storage. The storage uses an lucene index to store the enries. As + * modifying the index all the time an altering request comes in is not + * efficent. The entries will be added to the buffer to be available for + * incoming storage queries. If the loadfactor for the + * {@link org.apache.lucene.gdata.storage.lucenestorage.StorageModifier} is + * reached the modifier will perform a batch update on the index. Each entry + * will be associated with a feed id inside a associative datastructure to + * return a requested entry efficiently. + *

+ * This implementation uses {@link java.util.concurrent.locks.ReadWriteLock}. + * The read lock may be held simultaneously by multiple reader threads, so long + * as there are no writers. The write lock is exclusive. + *

+ * + * @see java.util.concurrent.locks.ReentrantReadWriteLock + * @see org.apache.lucene.gdata.storage.lucenestorage.StorageModifier + * @see org.apache.lucene.gdata.storage.lucenestorage.StorageCoreController + * + * @author Simon Willnauer + * + */ +public class StorageBuffer { + private static final Log LOG = LogFactory.getLog(StorageBuffer.class); - /** - * @see com.google.gdata.data.BaseEntry#declareExtensions(com.google.gdata.data.ExtensionProfile) - */ - @Override - public void declareExtensions(ExtensionProfile arg0) { - // - } - - } - -} + private final Map> bufferMap; + + private final Map modifiyMap; + + private final List excludeList; + + private final ReadWriteLock lock = new ReentrantReadWriteLock(true); + + private final Lock readLock = this.lock.readLock(); + + private final Lock writeLock = this.lock.writeLock(); + + private final static int DEFAULT_BUFFER_COUNT = 10; + + /** + * Constructs a new StorageBuffer. + *

+ * The expectedBufferCount sould be higher than the maximum of entries added + * to the buffer, resizing the buffer is very efficient. For detailed + * infomation {@link HashMap} as this is used inside the buffer + *

+ * + * @param expectedBufferCount - + * the expected size of the buffer + * + */ + protected StorageBuffer(final int expectedBufferCount) { + this.bufferMap = new HashMap>( + expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT + : expectedBufferCount); + this.excludeList = new ArrayList( + expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT + : expectedBufferCount); + this.modifiyMap = new HashMap( + expectedBufferCount < DEFAULT_BUFFER_COUNT ? DEFAULT_BUFFER_COUNT + : expectedBufferCount); + } + + /** + * Adds a {@link StorageEntryWrapper} to the buffer. If a wrapper + * representing the same entry are already in the buffer the wrapper will be + * replaced. + * + * @param wrapper - + * the wrapper to buffer + */ + public void addEntry(final StorageEntryWrapper wrapper) { + this.writeLock.lock(); + try { + if (LOG.isInfoEnabled()) + LOG.info(" Buffering wrapper - " + wrapper.getOperation() + + " ID: " + wrapper.getEntryId() + " FeedID: " + + wrapper.getFeedId()); + if (wrapper.getOperation().equals(StorageOperation.DELETE)) + return; + + String feedId = wrapper.getFeedId(); + if (this.bufferMap.containsKey(feedId)) + this.bufferMap.get(feedId).put(wrapper.getEntryId(), wrapper); + else { + Map newFeedMap = new HashMap( + 20); + newFeedMap.put(wrapper.getEntryId(), wrapper); + this.bufferMap.put(feedId, newFeedMap); + + } + addLastModified(wrapper.getFeedId(), wrapper.getTimestamp()); + } finally { + /* + * add all to exclude from searches doc will be available via the + * buffer + */ + this.excludeList.add(wrapper.getEntryId()); + this.writeLock.unlock(); + } + } + + private void addLastModified(final String feedId, Long timestamp) { + if (this.modifiyMap.containsKey(feedId)) + this.modifiyMap.remove(feedId); + this.modifiyMap.put(feedId, timestamp); + + } + + protected Long getFeedLastModified(final String feedId) { + return this.modifiyMap.get(feedId); + } + + protected Set> getLastModified() { + return this.modifiyMap.entrySet(); + } + + /** + * Returns all entries for the given feed id sorted by the update timestamp + * desc. + * + * @param feedId - + * the feed id + * @return a {@link List} of all {@link StorageEntryWrapper} object buffered + * in this buffer or an empty list if not entry has been buffered + * for the given feed + */ + public List getSortedEntries(String feedId) { + this.readLock.lock(); + try { + if (!this.bufferMap.containsKey(feedId)) + return null; + Map tempMap = this.bufferMap + .get(feedId); + if (tempMap == null) + return null; + Collection col = tempMap.values(); + List returnList = new ArrayList( + col); + Collections.sort(returnList); + return returnList; + + } finally { + this.readLock.unlock(); + } + + } + + /** + * Adds a deleted entry to the buffer. + * + * @param entryId - + * the deleted entry id + * @param feedId - + * the feed of the entry + */ + public void addDeleted(final String entryId, final String feedId) { + this.writeLock.lock(); + try { + this.excludeList.add(entryId); + Map tempMap = this.bufferMap + .get(feedId); + if (tempMap == null) + return; + tempMap.remove(entryId); + this.addLastModified(feedId, new Long(System.currentTimeMillis())); + } finally { + this.writeLock.unlock(); + + } + + } + + /** + * Returns an entry for the given entry id in the feed context spezified by + * the feed id; + * + * @param entryId - + * the id of the entry to return + * @param feedId - + * the feed containing the entry + * @return - the entry or null if the corresponding entry is + * not in the buffer. + */ + public StorageEntryWrapper getEntry(final String entryId, + final String feedId) { + this.readLock.lock(); + try { + + if (this.bufferMap.containsKey(feedId)) + return this.bufferMap.get(feedId).get(entryId); + return null; + + } finally { + this.readLock.unlock(); + } + } + + /** + * The buffer contains updated and delete entries. These entries are already + * available in the lucene index but should not be found during search. + * + *

+ * This list contains all entries should not be found by the index searcher. + * This method creates a copy of the current list to prevent concurrent + * modification exceptions while iteration over the collection. + *

+ * + * + * @see ModifiedEntryFilter + * @return - a String array of entries to be omitted from a lucene index + * search + */ + public String[] getExculdList() { + this.readLock.lock(); + try { + return this.excludeList + .toArray(new String[this.excludeList.size()]); + } finally { + this.readLock.unlock(); + } + } + + // not synchronized + private void clearBuffer() { + this.bufferMap.clear(); + this.excludeList.clear(); + this.modifiyMap.clear(); + + } + + /** + * clears the buffer - + */ + public void close() { + this.writeLock.lock(); + try { + clearBuffer(); + } finally { + this.writeLock.unlock(); + } + + } + + static class BufferableEntry extends BaseEntry { + + /** + * + */ + @SuppressWarnings("unchecked") + public BufferableEntry() { + super(); + this.links = new LinkedList(); + } + + /** + * @param arg0 + */ + @SuppressWarnings("unchecked") + public BufferableEntry(BaseEntry arg0) { + super(arg0); + this.links = new LinkedList(); + } + + /** + * @see com.google.gdata.data.BaseEntry#declareExtensions(com.google.gdata.data.ExtensionProfile) + */ + @Override + public void declareExtensions(ExtensionProfile arg0) { + // + } + + } + +} diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java index f168d3c288c..04b66a5cd18 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageCoreController.java @@ -2,6 +2,9 @@ package org.apache.lucene.gdata.storage.lucenestorage; import java.io.File; import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -42,8 +45,9 @@ public class StorageCoreController implements StorageController { private ReferenceCounter storageQuery; private StorageBuffer currentBuffer; - - private Object storageControllerLock = new Object(); + private final AtomicBoolean isClosed = new AtomicBoolean(false); + private final ReentrantLock storageControllerLock = new ReentrantLock(); + private final Condition closeCondition; private static final int DEFAULT_STORAGE_BUFFER_SIZE = 10; @@ -77,6 +81,7 @@ public class StorageCoreController implements StorageController { */ public StorageCoreController() throws IOException, StorageException { synchronized (StorageCoreController.class) { + this.closeCondition = this.storageControllerLock.newCondition(); try { this.idGenerator = new IDGenerator(10); } catch (Exception e) { @@ -168,8 +173,12 @@ public class StorageCoreController implements StorageController { * */ protected ReferenceCounter getStorageQuery() { - synchronized (this.storageControllerLock) { - + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + this.storageControllerLock.lock(); + try{ + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); if (this.storageQuery == null) { this.storageQuery = getNewStorageQueryHolder(new StorageQuery( this.currentBuffer, this.searcher)); @@ -178,6 +187,9 @@ public class StorageCoreController implements StorageController { } this.storageQuery.increamentReference(); return this.storageQuery; + }finally{ + this.closeCondition.signalAll(); + this.storageControllerLock.unlock(); } } @@ -185,7 +197,8 @@ public class StorageCoreController implements StorageController { final StorageQuery query) { ReferenceCounter holder = new ReferenceCounter( query) { - public void close() { + @Override + public void close() { try { if (LOG.isInfoEnabled()) LOG @@ -210,15 +223,24 @@ public class StorageCoreController implements StorageController { * if an IO exception occures */ protected void registerNewStorageQuery() throws IOException { - if (LOG.isInfoEnabled()) - LOG.info("new StorageQuery requested -- create new storage buffer"); - synchronized (this.storageControllerLock) { + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + this.storageControllerLock.lock(); + try{ + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + if (LOG.isInfoEnabled()) + LOG.info("new StorageQuery requested -- create new storage buffer"); + if (this.storageQuery != null) this.storageQuery.decrementRef(); this.searcher = new IndexSearcher(this.storageDir); this.storageQuery = null; this.currentBuffer = new StorageBuffer(this.storageBufferSize); + }finally{ + this.closeCondition.signalAll(); + this.storageControllerLock.unlock(); } } @@ -229,8 +251,16 @@ public class StorageCoreController implements StorageController { * @return the new StorageBuffer */ protected StorageBuffer releaseNewStorageBuffer() { - synchronized (this.storageControllerLock) { + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + this.storageControllerLock.lock(); + try{ + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); return this.currentBuffer; + }finally{ + this.closeCondition.signalAll(); + this.storageControllerLock.unlock(); } } @@ -242,23 +272,45 @@ public class StorageCoreController implements StorageController { * if an IO exception occures */ protected IndexModifier createIndexModifier() throws IOException { - if (LOG.isInfoEnabled()) - LOG.info("new IndexModifier created - release to StorageModifier"); - synchronized (this.storageControllerLock) { + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + this.storageControllerLock.lock(); + try{ + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + if (LOG.isInfoEnabled()) + LOG.info("new IndexModifier created - release to StorageModifier"); + return new IndexModifier(this.storageDir, new StandardAnalyzer(), false); + }finally{ + this.closeCondition.signalAll(); + this.storageControllerLock.unlock(); } } private void close() throws IOException { - synchronized (this.storageControllerLock) { + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + + this.storageControllerLock.lock(); + try{ + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); + this.isClosed.set(true); + while(this.storageControllerLock.getQueueLength()>0) + try{ + this.closeCondition.await(); + }catch (Exception e) { + // + } if (LOG.isInfoEnabled()) - LOG - .info("StorageController has been closed -- server is shutting down -- release all resources"); + LOG.info("StorageController has been closed -- server is shutting down -- release all resources"); if (this.storageQuery != null) this.storageQuery.decrementRef(); this.modifier.close(); - // TODO make sure all resources will be released + }finally{ + this.storageControllerLock.unlock(); } } @@ -307,6 +359,8 @@ public class StorageCoreController implements StorageController { * */ public void forceWrite() throws IOException { + if(this.isClosed.get()) + throw new IllegalStateException("StorageController is already closed -- server is shutting down"); this.modifier.forceWrite(); } diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java index d9aa68f4d00..005040431bf 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/storage/lucenestorage/StorageModifier.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -67,10 +68,12 @@ public class StorageModifier { private IndexModifier modifier; private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false); + + private final AtomicBoolean isClosed = new AtomicBoolean(false); + + private final Lock readLock = this.lock.readLock(); - private Lock readLock = this.lock.readLock(); - - private Lock writeLock = this.lock.writeLock(); + private final Lock writeLock = this.lock.writeLock(); private final static int DEFAULT_OPTIMIZE_INTERVAL = 10; @@ -315,10 +318,14 @@ public class StorageModifier { } private void storageModified() throws StorageException { + if(this.isClosed.get()) + throw new IllegalStateException("StorageModifier is already closed"); this.readLock.unlock(); this.writeLock.lock(); try { + if(this.isClosed.get()) + throw new IllegalStateException("StorageModifier is already closed"); incrementCounter(); if (this.persistFactor > this.modifiedCounter && this.forceWriteDocuments.size() <= 0 @@ -345,6 +352,8 @@ public class StorageModifier { } protected void forceWrite() throws IOException { + if(this.isClosed.get()) + throw new IllegalStateException("StorageModifier is already closed"); this.writeLock.lock(); try { if (LOG.isInfoEnabled()) @@ -424,8 +433,13 @@ public class StorageModifier { } protected void close() throws IOException { + if(this.isClosed.get()) + throw new IllegalStateException("StorageModifier is already closed"); this.writeLock.lock(); try { + if(this.isClosed.get()) + throw new IllegalStateException("StorageModifier is already closed"); + this.isClosed.set(true); if (LOG.isInfoEnabled()) LOG.info("ForceWrite called -- current modifiedCounter: " + this.modifiedCounter + " - persisting changes"); diff --git a/contrib/gdata-server/src/java/org/apache/lucene/gdata/utils/DateFormater.java b/contrib/gdata-server/src/java/org/apache/lucene/gdata/utils/DateFormater.java index 20778d0046b..adc62f72e0f 100644 --- a/contrib/gdata-server/src/java/org/apache/lucene/gdata/utils/DateFormater.java +++ b/contrib/gdata-server/src/java/org/apache/lucene/gdata/utils/DateFormater.java @@ -19,6 +19,7 @@ package org.apache.lucene.gdata.utils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.Stack; /** @@ -106,6 +107,7 @@ public class DateFormater { if(dateString == null|| pattern == null) throw new IllegalArgumentException( "given parameters must not be null"); + SimpleDateFormat inst = formater.getFormater(); inst.applyPattern(pattern); return inst.parse(dateString); @@ -113,7 +115,7 @@ public class DateFormater { private SimpleDateFormat getFormater() { if (this.objectStack.empty()) - return new SimpleDateFormat(); + return new SimpleDateFormat(DateFormater.HTTP_HEADER_DATE_FORMAT,Locale.ENGLISH); return this.objectStack.pop(); } diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java index cd4bf510c5a..1bcc9235f45 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestModifiedEntryFilter.java @@ -55,11 +55,11 @@ public class TestModifiedEntryFilter extends TestCase { Hits hits = s.search(q); assertEquals(2,hits.length()); - hits = s.search(q,new ModifiedEntryFilter(this.excludeList)); + hits = s.search(q,new ModifiedEntryFilter(this.excludeList.toArray(new String[0]))); assertEquals(1,hits.length()); this.excludeList.add("2"); - hits = s.search(q,new ModifiedEntryFilter(this.excludeList)); + hits = s.search(q,new ModifiedEntryFilter(this.excludeList.toArray(new String[0]))); assertEquals(0,hits.length()); } diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java index eff4d6146f5..3bac2437927 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/storage/lucenestorage/TestStorageModifier.java @@ -136,16 +136,27 @@ public class TestStorageModifier extends TestCase { Thread b = getRunnerThread((this.count += 10)); b.start(); - a.join(); + // wait for the first thread to check for the inserted entries + a.join(); + try{ for (int i = 1; i < this.count; i++) { ReferenceCounter innerQuery = this.controller .getStorageQuery(); BaseEntry e = innerQuery.get().singleEntryQuery("" + i, feedId, this.configurator); + assertNotNull(e); assertEquals("get entry for id" + i, "" + i, e.getId()); } - b.join(); + }finally{ + /* + * if an exception occures the tread can at least finnish running before the + * controller will be closed in the tearDown method + */ + b.join(); + } + + ReferenceCounter query = this.controller .getStorageQuery(); diff --git a/contrib/gdata-server/src/test/org/apache/lucene/gdata/utils/TestDateFormater.java b/contrib/gdata-server/src/test/org/apache/lucene/gdata/utils/TestDateFormater.java index a632c5e4021..e5b44f3ec90 100644 --- a/contrib/gdata-server/src/test/org/apache/lucene/gdata/utils/TestDateFormater.java +++ b/contrib/gdata-server/src/test/org/apache/lucene/gdata/utils/TestDateFormater.java @@ -25,13 +25,16 @@ public class TestDateFormater extends TestCase { public void testFormatDate() throws ParseException { // this reg. --> bit weak but does the job - java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("[A-Z][a-z]{2}, [0-9]{1,2} [A-Z][a-z]{2} [0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [A-Z]{2,4}"); + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("[A-Z][a-z]{1,2}, [0-9]{1,2} [A-Z][a-z]{2} [0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [A-Z]{2,4}"); Date date = new Date(); - System.out.println(date.getTime()); + String formatedDate = DateFormater.formatDate(date,DateFormater.HTTP_HEADER_DATE_FORMAT); + assertTrue(pattern.matcher(formatedDate).matches()); - System.out.println(DateFormater.parseDate(formatedDate,DateFormater.HTTP_HEADER_DATE_FORMAT).getTime()); - DateFormater.parseDate("Sun, 25 Jun 2006 13:51:23 +0000",DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET); + + DateFormater.parseDate("Sun, 25 Jun 2006 13:51:23 CEST",DateFormater.HTTP_HEADER_DATE_FORMAT,DateFormater.HTTP_HEADER_DATE_FORMAT_TIME_OFFSET); + //TODO extend this + }