[infinispan-commits] Infinispan SVN: r957 - in trunk/lucene-directory: src/main/java and 8 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Thu Oct 15 19:59:00 EDT 2009
Author: sannegrinovero
Date: 2009-10-15 19:59:00 -0400 (Thu, 15 Oct 2009)
New Revision: 957
Added:
trunk/lucene-directory/src/main/java/org/
trunk/lucene-directory/src/main/java/org/infinispan/
trunk/lucene-directory/src/main/java/org/infinispan/lucene/
trunk/lucene-directory/src/main/java/org/infinispan/lucene/CacheKey.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/ChunkCacheKey.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileCacheKey.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileListCacheKey.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileMetadata.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanCacheEntryListener.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanIndexIO.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java
trunk/lucene-directory/src/test/java/org/
trunk/lucene-directory/src/test/java/org/infinispan/
trunk/lucene-directory/src/test/java/org/infinispan/lucene/
trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java
trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanCacheEntryListenerTest.java
trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryIOTest.java
trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryStressTest.java
trunk/lucene-directory/src/test/java/org/infinispan/lucene/SimpleLuceneTest.java
trunk/lucene-directory/src/test/resources/
Modified:
trunk/lucene-directory/
trunk/lucene-directory/pom.xml
Log:
[ISPN-218] (Create a distributed Lucene Directory based on Infinispan)
Property changes on: trunk/lucene-directory
___________________________________________________________________
Name: svn:ignore
+ .settings
target
.classpath
.project
test-output
temp-testng-customsuite.xml
ObjectStore
Modified: trunk/lucene-directory/pom.xml
===================================================================
--- trunk/lucene-directory/pom.xml 2009-10-15 14:29:48 UTC (rev 956)
+++ trunk/lucene-directory/pom.xml 2009-10-15 23:59:00 UTC (rev 957)
@@ -2,6 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.infinispan</groupId>
@@ -13,6 +14,11 @@
<artifactId>infinispan-lucene-directory</artifactId>
<name>Infinispan Lucene Directory Implementation</name>
<description>A Lucene directory implementation based on Infinispan</description>
+
+ <properties>
+ <version.lucene>2.4.1</version.lucene>
+ </properties>
+
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
@@ -21,6 +27,12 @@
</dependency>
<dependency>
+ <groupId>org.apache.lucene</groupId>
+ <artifactId>lucene-core</artifactId>
+ <version>${version.lucene}</version>
+ </dependency>
+
+ <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>infinispan-core</artifactId>
<version>${project.version}</version>
@@ -28,4 +40,5 @@
<scope>test</scope>
</dependency>
</dependencies>
+
</project>
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/CacheKey.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/CacheKey.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/CacheKey.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.Serializable;
+
+/**
+ * Abstract class used as a key for Infinispan cache to distinct its values. Connection of fields:
+ * indexName and fileName is unique, even if we share one cache between all DirectoryProvider's
+ *
+ * @author Lukasz Moren
+ * @since 4.0
+ * @see org.hibernate.search.store.infinispan.InfinispanDirectory#cache
+ */
+public abstract class CacheKey implements Serializable {
+
+ protected final String indexName;
+ protected final String fileName;
+
+ protected int hashCode;
+
+ protected CacheKey(String indexName, String fileName) {
+ this.indexName = indexName;
+ this.fileName = fileName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ CacheKey that = (CacheKey) o;
+
+ if (fileName != null ? !fileName.equals(that.fileName) : that.fileName != null) {
+ return false;
+ }
+ if (indexName != null ? !indexName.equals(that.indexName) : that.indexName != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ hashCode = indexName != null ? indexName.hashCode() : 0;
+ hashCode = 31 * hashCode + (fileName != null ? fileName.hashCode() : 0);
+ hashCode = 31 * hashCode + (this.getClass().getName() != null ? this.getClass().getName().hashCode() : 0);
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "CacheKey{" + "fileName='" + fileName + '\'' + ", indexName='" + indexName + '\'' + '}';
+ }
+
+ public final String getIndexName() {
+ return indexName;
+ }
+
+ public final String getFileName() {
+ return fileName;
+ }
+
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/CacheKey.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/ChunkCacheKey.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/ChunkCacheKey.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/ChunkCacheKey.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,85 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.Serializable;
+
+/**
+ * Used as a key to distinguish file chunk in cache.
+ *
+ * @author Lukasz Moren
+ */
+public class ChunkCacheKey extends CacheKey implements Serializable {
+
+ protected final Integer chunkId;
+
+ public ChunkCacheKey(String indexName, String fileName, Integer chunkId) {
+ super(indexName, fileName);
+ this.chunkId = chunkId;
+ }
+
+ public Integer getChunkId() {
+ return Integer.valueOf(chunkId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+
+ ChunkCacheKey that = (ChunkCacheKey) o;
+
+ if (fileName != null ? !fileName.equals(that.fileName) : that.fileName != null) {
+ return false;
+ }
+ if (indexName != null ? !indexName.equals(that.indexName) : that.indexName != null) {
+ return false;
+ }
+
+ if (chunkId != null ? !chunkId.equals(that.chunkId) : that.chunkId != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ hashCode = super.hashCode();
+ hashCode = 31 * hashCode + (chunkId != null ? chunkId.hashCode() : 0);
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "ChunkCacheKey{" + "chunkId=" + chunkId + "} " + super.toString();
+ }
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/ChunkCacheKey.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileCacheKey.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileCacheKey.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileCacheKey.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,86 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.Serializable;
+
+/**
+ * Used as a key for file headers in a cache
+ *
+ * @author Lukasz Moren
+ */
+public class FileCacheKey extends CacheKey implements Serializable {
+
+ protected final boolean isLockKey;
+
+ public FileCacheKey(String indexName, String fileName) {
+ this(indexName, fileName, false);
+ }
+
+ public FileCacheKey(String indexName, String fileName, boolean isLockKey) {
+ super(indexName, fileName);
+ this.isLockKey = isLockKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+
+ FileCacheKey that = (FileCacheKey) o;
+
+ if (fileName != null ? !fileName.equals(that.fileName) : that.fileName != null) {
+ return false;
+ }
+ if (indexName != null ? !indexName.equals(that.indexName) : that.indexName != null) {
+ return false;
+ }
+
+ if (isLockKey != that.isLockKey) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode == 0) {
+ hashCode = super.hashCode();
+ hashCode = 31 * hashCode + (isLockKey ? 1 : 0);
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "CacheKey{" + "fileName='" + getFileName() + '\'' + "indexName='" + getIndexName() + '\'' + "isLockKey='"
+ + isLockKey + '\'' + '}';
+ }
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileCacheKey.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileListCacheKey.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileListCacheKey.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileListCacheKey.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+/**
+ * Cache key for a list with current files in cache
+ *
+ * @author Lukasz Moren
+ */
+public class FileListCacheKey extends CacheKey {
+
+ public FileListCacheKey(String indexName) {
+ super(indexName, "");
+ }
+
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileListCacheKey.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileMetadata.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileMetadata.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileMetadata.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.Serializable;
+
+/**
+ * Header for Lucene files. Store only basic info about file. File data is divided into byte[]
+ * chunks and stored under {@link org.hibernate.search.store.infinispan.ChunkCacheKey}
+ *
+ * @author Lukasz Moren
+ * @see org.hibernate.search.store.infinispan.FileCacheKey
+ */
+public class FileMetadata implements Serializable {
+
+ private long lastModified;
+ private long size = 0;
+
+ public FileMetadata() {
+ touch();
+ }
+
+ private void touch() {
+ setLastModified(System.currentTimeMillis());
+ }
+
+ public long getLastModified() {
+ return lastModified;
+ }
+
+ public void setLastModified(long lastModified) {
+ this.lastModified = lastModified;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ FileMetadata metadata = (FileMetadata) o;
+
+ return lastModified == metadata.lastModified && size == metadata.size;
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) (lastModified ^ (lastModified >>> 32));
+ result = 31 * result + (int) (size ^ (size >>> 32));
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "FileMetadata{" + "lastModified=" + lastModified + ", size=" + size + '}';
+ }
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/FileMetadata.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanCacheEntryListener.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanCacheEntryListener.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanCacheEntryListener.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.util.Map;
+
+import org.infinispan.Cache;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntryEvent;
+import org.infinispan.notifications.cachelistener.event.Event;
+
+/**
+ * Infinispan cache listener
+ *
+ * @author Lukasz Moren
+ */
+ at Listener
+public class InfinispanCacheEntryListener {
+
+ private final String indexName;
+
+ public InfinispanCacheEntryListener(String indexName) {
+ this.indexName = indexName;
+ }
+
+ /**
+ * Updates current Lucene file list in a cache - when cache entry is created or removed
+ *
+ * @param event Infinispan event
+ */
+ @SuppressWarnings( { "unchecked" })
+ @CacheEntryCreated
+ @CacheEntryRemoved
+ public void cacheEntryCreatedListener(CacheEntryEvent event) {
+ Object ob = event.getKey();
+ // process only local events
+ if (ob instanceof FileCacheKey && event.isOriginLocal()) {
+ FileCacheKey key = (FileCacheKey) ob;
+
+ if (key.getIndexName().equals(indexName) && !key.isLockKey) {
+ FileListCacheKey fileListKey = new FileListCacheKey(key.getIndexName());
+ Cache<CacheKey, Object> cache = event.getCache();
+ Map<String, String> fileList = (Map<String, String>) cache.get(fileListKey);
+
+ if (event.getType().equals(Event.Type.CACHE_ENTRY_CREATED)) {
+ fileList.put(key.getFileName(), key.getFileName());
+ } else if (event.getType().equals(Event.Type.CACHE_ENTRY_REMOVED)) {
+ fileList.remove(key.getFileName());
+ }
+
+ cache.put(fileListKey, fileList);
+ }
+ }
+ }
+
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanCacheEntryListener.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,246 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.store.AlreadyClosedException;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.IndexOutput;
+import org.apache.lucene.store.LockFactory;
+import org.infinispan.Cache;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Implementation that uses Infinispan to store Lucene indices
+ * <p/>
+ * Directory locking is assured with
+ * {@link org.hibernate.search.store.infinispan.InfinispanLockFactory.InfinispanLock}
+ *
+ * @author Lukasz Moren
+ * @author Sanne Grinovero
+ * @see org.hibernate.search.store.infinispan.InfinispanLockFactory
+ */
+// todo add support for ConcurrentMergeSheduler
+public class InfinispanDirectory extends Directory {
+
+ private static final Log log = LogFactory.getLog(InfinispanDirectory.class);
+
+ // own flag required if we are not in this same package what org.apache.lucene.store.Directory,
+ // access type will be changed in the next Lucene version
+ volatile boolean isOpen = true;
+
+ private Cache<CacheKey, Object> cache;
+ // indexName is required when one common cache is used
+ private String indexName;
+ // chunk size used in this directory, static filed not used as we want to have different chunk
+ // size per dir
+ private int chunkSize;
+
+ public InfinispanDirectory(Cache<CacheKey, Object> cache, String indexName, LockFactory lf, int chunkSize) {
+ this.cache = cache;
+ this.indexName = indexName;
+ this.setLockFactory(lf);
+ this.chunkSize = chunkSize;
+
+ // fixme change it to ConcurrentHashMap when [JBMAR-68] bug is fixed
+ // Infinispan does not provide efficient API (existing .keySet() is not recommended for
+ // production use) to retrieve list of available
+ // objects in cache. One entry in cache, store list of lucene file names.
+ cache.put(new FileListCacheKey(indexName), Collections.synchronizedMap(new HashMap<String, String>()));
+ // register listener which add/remove file names to/from above list
+ cache.addListener(new InfinispanCacheEntryListener(indexName));
+ }
+
+ public InfinispanDirectory(Cache<CacheKey, Object> cache, String indexName, LockFactory lf) {
+ this(cache, indexName, lf, InfinispanIndexIO.DEFAULT_BUFFER_SIZE);
+ }
+
+ public InfinispanDirectory(Cache<CacheKey, Object> cache, String indexName, int chunkSize) {
+ this(cache, indexName, new InfinispanLockFactory(cache, indexName), chunkSize);
+ }
+
+ public InfinispanDirectory(Cache<CacheKey, Object> cache, String indexName) {
+ this(cache, indexName, new InfinispanLockFactory(cache, indexName), InfinispanIndexIO.DEFAULT_BUFFER_SIZE);
+ }
+
+ public InfinispanDirectory(Cache<CacheKey, Object> cache) {
+ this(cache, "");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public synchronized String[] list() throws IOException {
+ checkIsOpen();
+ Map<String, String> filesList = (Map<String, String>) cache.get(new FileListCacheKey(indexName));
+ return (String[]) filesList.values().toArray(new String[] {});
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean fileExists(String name) throws IOException {
+ checkIsOpen();
+ return cache.containsKey(new FileCacheKey(indexName, name));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long fileModified(String name) throws IOException {
+ checkIsOpen();
+ FileMetadata file = getFile(indexName, name);
+ if (file == null) {
+ throw new FileNotFoundException(name);
+ }
+ return file.getLastModified();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void touchFile(String name) throws IOException {
+ checkIsOpen();
+ FileMetadata file = getFile(indexName, name);
+ if (file == null) {
+ throw new FileNotFoundException(name);
+ }
+ file.setLastModified(System.currentTimeMillis());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void deleteFile(String name) throws IOException {
+ checkIsOpen();
+ CacheKey key = new FileCacheKey(indexName, name);
+ // remove main file
+ cache.remove(key);
+ // and all of its chunks
+ int i = 0;
+ Object removed;
+ ChunkCacheKey chunkKey = new ChunkCacheKey(indexName, name, i);
+ do {
+ removed = cache.remove(chunkKey);
+ chunkKey = new ChunkCacheKey(indexName, name, ++i);
+ } while (removed != null);
+ if (log.isDebugEnabled()) {
+ log.debug("Removed file: {} from index: {}", new Object[] { key.getFileName(), indexName });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void renameFile(String from, String to) throws IOException {
+ checkIsOpen();
+ // rename main file header
+ FileMetadata fileFrom = getFile(indexName, from);
+ cache.remove(new FileCacheKey(indexName, from));
+ cache.put(new FileCacheKey(indexName, to), fileFrom);
+ // rename also all chunks
+ int i = -1;
+ Object ob;
+ do {
+ ChunkCacheKey chunkKey = new ChunkCacheKey(indexName, from, ++i);
+ ob = cache.get(chunkKey);
+ if (ob == null) {
+ break;
+ }
+ chunkKey = new ChunkCacheKey(indexName, to, i);
+ cache.put(chunkKey, ob);
+ } while (true);
+ if (log.isTraceEnabled()) {
+ log.trace("Renamed file from: {} to: {} in index {}", new Object[] { from, to, indexName });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized long fileLength(String name) throws IOException {
+ checkIsOpen();
+ final FileMetadata file = getFile(indexName, name);
+ if (file == null) {
+ throw new FileNotFoundException(name);
+ }
+ return file.getSize();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized IndexOutput createOutput(String name) throws IOException {
+ final CacheKey key = new FileCacheKey(indexName, name);
+ if (!fileExists(name)) {
+ cache.put(key, new FileMetadata());
+ }
+ return new InfinispanIndexIO.InfinispanIndexOutput(cache, key, chunkSize);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IndexInput openInput(String name) throws IOException {
+ final FileCacheKey fileKey = new FileCacheKey(indexName, name);
+ return new InfinispanIndexIO.InfinispanIndexInput(cache, fileKey, chunkSize);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() throws IOException {
+ isOpen = false;
+ if (cache != null) {
+ cache.stop();
+ cache = null;
+ }
+ }
+
+ private void checkIsOpen() throws AlreadyClosedException {
+ if (!isOpen) {
+ throw new AlreadyClosedException("this Directory is closed");
+ }
+ }
+
+ private FileMetadata getFile(String indexName, String fileName) {
+ CacheKey key = new FileCacheKey(indexName, fileName);
+ return (FileMetadata) cache.get(key);
+ }
+
+ @Override
+ public String toString() {
+ return "InfinispanDirectory{" + "indexName='" + indexName + '\'' + '}';
+ }
+
+ public Cache<CacheKey, Object> getCache() {
+ return cache;
+ }
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanDirectory.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanIndexIO.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanIndexIO.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanIndexIO.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,317 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+
+import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.IndexOutput;
+import org.infinispan.Cache;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Deal with input-output operations on Infinispan based Directory
+ *
+ * @author Lukasz Moren
+ * @see org.apache.lucene.store.Directory
+ * @see org.apache.lucene.store.IndexInput
+ * @see org.apache.lucene.store.IndexOutput
+ */
+public class InfinispanIndexIO {
+
+ // used as default chunk size if not provided in conf
+ // each Lucene index is splitted into parts with default size defined here
+ public final static int DEFAULT_BUFFER_SIZE = 16 * 1024;
+
+ private static byte[] getChunkFromPosition(Map<CacheKey, Object> cache, CacheKey fileKey, int pos, int bufferSize) {
+ CacheKey key = new ChunkCacheKey(fileKey.getIndexName(), fileKey.getFileName(), getChunkNumberFromPosition(pos,
+ bufferSize));
+ return (byte[]) cache.get(key);
+ }
+
+ private static int getPositionInBuffer(int pos, int bufferSize) {
+ return (pos % bufferSize);
+ }
+
+ private static int getChunkNumberFromPosition(int pos, int bufferSize) {
+ return ((pos) / (bufferSize));
+ }
+
+ /**
+ * Responsible for writing into <code>Directory</code>
+ */
+ public static class InfinispanIndexInput extends IndexInput {
+
+ private static final Log log = LogFactory.getLog(InfinispanIndexInput.class);
+
+ private final int bufferSize;
+
+ private Cache<CacheKey, Object> cache;
+ private ConcurrentHashMap<CacheKey, Object> localCache = new ConcurrentHashMap<CacheKey, Object>();
+ private FileMetadata file;
+ private CacheKey fileKey;
+ private byte[] buffer;
+ private int bufferPosition = 0;
+ private int filePosition = 0;
+
+ public InfinispanIndexInput(Cache<CacheKey, Object> cache, CacheKey fileKey) throws IOException {
+ this(cache, fileKey, InfinispanIndexIO.DEFAULT_BUFFER_SIZE);
+ }
+
+ public InfinispanIndexInput(Cache<CacheKey, Object> cache, CacheKey fileKey, int bufferSize) throws IOException {
+ this.cache = cache;
+ this.fileKey = fileKey;
+ this.bufferSize = bufferSize;
+ buffer = new byte[this.bufferSize];
+
+ // get file header from file
+ this.file = (FileMetadata) cache.get(fileKey);
+
+ if (file == null) {
+ throw new IOException("File [ " + fileKey.getFileName() + " ] for index [ " + fileKey.getIndexName()
+ + " ] was not found");
+ }
+
+ // get records to local cache
+ int i = 0;
+ Object fileChunk;
+ ChunkCacheKey chunkKey = new ChunkCacheKey(fileKey.getIndexName(), fileKey.getFileName(), i);
+ while ((fileChunk = cache.get(chunkKey)) != null) {
+ localCache.put(chunkKey, fileChunk);
+ chunkKey = new ChunkCacheKey(fileKey.getIndexName(), fileKey.getFileName(), ++i);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Opened new IndexInput for file:{} in index: {}", fileKey.getFileName(), fileKey.getIndexName());
+ }
+ }
+
+ private byte[] getChunkFromPosition(Cache<CacheKey, Object> cache, CacheKey fileKey, int pos, int bufferSize) {
+ Object object = InfinispanIndexIO.getChunkFromPosition(cache, fileKey, pos, bufferSize);
+ if (object == null) {
+ object = InfinispanIndexIO.getChunkFromPosition(localCache, fileKey, pos, bufferSize);
+ }
+ return (byte[]) object;
+ }
+
+ public byte readByte() throws IOException {
+ if (file == null) {
+ throw new IOException("File " + fileKey + " does not exist");
+ }
+
+ if (filePosition == 0 && file.getSize() == 0) {
+ if (log.isTraceEnabled()) {
+ log.trace("pointer and file sizes are both 0; returning -1");
+ }
+ return -1;
+ }
+
+ buffer = getChunkFromPosition(cache, fileKey, filePosition, bufferSize);
+ if (buffer == null) {
+ throw new IOException("Chunk id = [ " + getChunkNumberFromPosition(filePosition, bufferSize)
+ + " ] does not exist for file [ " + fileKey.getFileName() + " ] for index [ "
+ + fileKey.getIndexName() + " ]");
+ }
+
+ bufferPosition = getPositionInBuffer(filePosition++, bufferSize);
+ return buffer[bufferPosition];
+ }
+
+ public void readBytes(byte[] b, int offset, int len) throws IOException {
+
+ if (file == null) {
+ throw new IOException("(null): File does not exist");
+ }
+
+ if (filePosition == 0 && file.getSize() == 0) {
+ if (log.isTraceEnabled()) {
+ log.trace("pointer and file sizes are both 0; returning -1");
+ }
+ }
+
+ int bytesToRead = len;
+ while (bytesToRead > 0) {
+ buffer = getChunkFromPosition(cache, fileKey, filePosition, bufferSize);
+ if (buffer == null) {
+ throw new IOException("Chunk id = [ " + getChunkNumberFromPosition(filePosition, bufferSize)
+ + " ] does not exist for file [ " + fileKey.getFileName() + " ] for index [ "
+ + fileKey.getIndexName() + " ], file position: [ " + filePosition + " ], file size: [ "
+ + file.getSize() + " ]");
+ }
+ bufferPosition = getPositionInBuffer(filePosition, bufferSize);
+ int bytesToCopy = Math.min(buffer.length - bufferPosition, bytesToRead);
+ System.arraycopy(buffer, bufferPosition, b, offset, bytesToCopy);
+ offset += bytesToCopy;
+ bytesToRead -= bytesToCopy;
+ filePosition += bytesToCopy;
+ }
+ }
+
+ public void close() throws IOException {
+ filePosition = 0;
+ bufferPosition = 0;
+ buffer = null;
+ localCache = null;
+ if (log.isDebugEnabled()) {
+ log.debug("Closed IndexInput for file:{} in index: {}", fileKey.getFileName(), fileKey.getIndexName());
+ }
+ }
+
+ public long getFilePointer() {
+ return filePosition;
+ }
+
+ public void seek(long pos) throws IOException {
+ filePosition = (int) pos;
+ }
+
+ public long length() {
+ return file.getSize();
+ }
+ }
+
+ /**
+ * Responsible for reading from <code>Directory</code>
+ */
+ public static class InfinispanIndexOutput extends IndexOutput {
+
+ private static final Log log = LogFactory.getLog(InfinispanIndexOutput.class);
+
+ private final int bufferSize;
+
+ private Cache<CacheKey, Object> cache;
+ private FileMetadata file;
+ private CacheKey fileKey;
+
+ private byte[] buffer;
+ private int bufferPosition = 0;
+ private int filePosition = 0;
+ private int chunkNumber;
+
+ public InfinispanIndexOutput(Cache<CacheKey, Object> cache, CacheKey fileKey) throws IOException {
+ this(cache, fileKey, InfinispanIndexIO.DEFAULT_BUFFER_SIZE);
+ }
+
+ public InfinispanIndexOutput(Cache<CacheKey, Object> cache, CacheKey fileKey, int bufferSize) throws IOException {
+ this.cache = cache;
+ this.fileKey = fileKey;
+ this.bufferSize = bufferSize;
+
+ buffer = new byte[this.bufferSize];
+
+ this.file = (FileMetadata) cache.get(fileKey);
+ if (log.isDebugEnabled()) {
+ log.debug("Opened new IndexOutput for file:{} in index: {}", fileKey.getFileName(), fileKey.getIndexName());
+ }
+ }
+
+ private void newChunk() throws IOException {
+ flush();// save data first
+
+ // check if we have to create new chunk, or get already existing in cache for modification
+ if ((buffer = getChunkFromPosition(cache, fileKey, filePosition, bufferSize)) == null) {
+ buffer = new byte[bufferSize];
+ }
+ bufferPosition = 0;
+ }
+
+ public void writeByte(byte b) throws IOException {
+ if (isNewChunkNeeded()) {
+ newChunk();
+ }
+ buffer[bufferPosition++] = b;
+ filePosition++;
+ }
+
+ public void writeBytes(byte[] b, int offset, int length) throws IOException {
+
+ int writedBytes = 0;
+ while (writedBytes < length) {
+ int pieceLength = Math.min(buffer.length - bufferPosition, length - writedBytes);
+ System.arraycopy(b, offset + writedBytes, buffer, bufferPosition, pieceLength);
+ bufferPosition += pieceLength;
+ filePosition += pieceLength;
+ writedBytes += pieceLength;
+ if (isNewChunkNeeded()) {
+ newChunk();
+ }
+ }
+ }
+
+ private boolean isNewChunkNeeded() {
+ return (bufferPosition == buffer.length);
+ }
+
+ public void flush() throws IOException {
+ // select right chunkNumber
+ chunkNumber = getChunkNumberFromPosition(filePosition - 1, bufferSize);
+ // and create distinct key for it
+ ChunkCacheKey key = new ChunkCacheKey(fileKey.getIndexName(), fileKey.getFileName(), chunkNumber);
+ // size changed, apply change to file header
+ setFileLength();
+ // add chunk to cache
+ cache.put(key, buffer);
+ // override existing file header with new size and last time acess
+ cache.put(fileKey, file);
+ }
+
+ public void close() throws IOException {
+ flush();
+ bufferPosition = 0;
+ filePosition = 0;
+ buffer = null;
+ if (log.isDebugEnabled()) {
+ log.debug("Closed IndexOutput for file:{} in index: {}", fileKey.getFileName(), fileKey.getIndexName());
+ }
+ }
+
+ public long getFilePointer() {
+ return filePosition;
+ }
+
+ public void seek(long pos) throws IOException {
+ flush();
+
+ if (pos > file.getSize()) {
+ throw new IOException(fileKey.getFileName() + ": seeking past of the file");
+ }
+
+ buffer = getChunkFromPosition(cache, fileKey, (int) pos, bufferSize);
+ bufferPosition = getPositionInBuffer((int) pos, bufferSize);
+ filePosition = (int) pos;
+ }
+
+ public long length() throws IOException {
+ return file.getSize();
+ }
+
+ protected void setFileLength() {
+ file.setLastModified(System.currentTimeMillis());
+ if (file.getSize() < filePosition) {
+ file.setSize(filePosition);
+ }
+ }
+ }
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanIndexIO.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java (rev 0)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,225 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.IOException;
+import javax.transaction.RollbackException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.lucene.store.Lock;
+import org.apache.lucene.store.LockFactory;
+import org.infinispan.Cache;
+import org.infinispan.CacheException;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * Factory for locks obtained in <code>InfinispanDirectory</code>
+ *
+ * @author Lukasz Moren
+ * @see org.hibernate.search.store.infinispan.InfinispanDirectory
+ * @see org.hibernate.search.store.infinispan.InfinispanLockFactory.InfinispanLock
+ */
+public class InfinispanLockFactory extends LockFactory {
+
+ private static final Log log = LogFactory.getLog(InfinispanLockFactory.class);
+
+ private Cache<CacheKey, Object> cache;
+ private String indexName;
+
+ public InfinispanLockFactory(Cache<CacheKey, Object> cache, String indexName) {
+ this.cache = cache;
+ this.indexName = indexName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Lock makeLock(String lockName) {
+ try {
+ return new InfinispanLock(cache, indexName, lockName);
+ } finally {
+ if (log.isTraceEnabled()) {
+ log.trace("Created new lock: {} for index {}", lockName, indexName);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void clearLock(String lockName) throws IOException {
+ try {
+ cache.remove(new FileCacheKey(indexName, lockName, true));
+ } finally {
+ if (log.isTraceEnabled()) {
+ log.trace("Removed lock: {} for index {}", lockName, indexName);
+ }
+ }
+ }
+
+ /**
+ * Interprocess Lucene index lock
+ *
+ * @see org.apache.lucene.store.Directory#makeLock(String)
+ */
+ public static class InfinispanLock extends Lock {
+
+ private static final Log log = LogFactory.getLog(InfinispanLock.class);
+
+ private final Cache<CacheKey, Object> cache;
+ private String lockName;
+ private String indexName;
+
+ final TransactionManager tm;
+
+ InfinispanLock(Cache<CacheKey, Object> cache, String indexName, String lockName) {
+ this.cache = cache;
+ this.lockName = lockName;
+ this.indexName = indexName;
+
+ tm = cache.getAdvancedCache().getComponentRegistry().getComponent(TransactionManager.class);
+ if (tm == null) {
+ throw new CacheException(
+ "Failed looking up TransactionManager, check if any transaction manager is associated with Infinispan cache: "
+ + cache.getName());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean obtain() throws IOException {
+ boolean acquired = false;
+
+ synchronized (cache) {
+ try {
+ // begin transaction for lock obtaining
+ tm.begin();
+ CacheKey lock = new FileCacheKey(indexName, lockName, true);
+ if (!cache.containsKey(lock)) {
+ cache.put(lock, lock);
+ acquired = true;
+ }
+ } catch (Exception e) {
+ log.error("Cannot obtain lock for: " + indexName, e);
+ } finally {
+ try {
+ if (tm.getTransaction() != null) {
+ if (acquired) {
+ tm.commit();
+ if (log.isTraceEnabled()) {
+ log.trace("Lock: {} acquired for index: {} ", new Object[] { lockName, indexName });
+ }
+ } else {
+ tm.rollback();
+ }
+ }
+ } catch (RollbackException e) {
+ log.error("Cannot obtain lock for: " + indexName, e);
+ acquired = false;
+ } catch (Exception e) {
+ throw new CacheException(e);
+ }
+ }
+
+ if (acquired) {
+ try {
+ // begin new transaction to batch all changes, tx commited when lock is released.
+ tm.begin();
+ if (log.isTraceEnabled()) {
+ log.trace("Batch transaction started for index: {}", indexName);
+ }
+ } catch (Exception e) {
+ log.error("Unable to start transaction", e);
+ }
+ }
+ }
+
+ return acquired;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void release() throws IOException {
+ boolean removed = false;
+ synchronized (cache) {
+ try {
+ // commit changes in batch, transaction was started when lock was acquired
+ tm.commit();
+ if (log.isTraceEnabled()) {
+ log.trace("Batch transaction commited for index: {}", indexName);
+ }
+
+ tm.begin();
+ removed = cache.remove(new FileCacheKey(indexName, lockName, true)) != null;
+ } catch (Exception e) {
+ throw new CacheException("Unable to commit work done or release lock!", e);
+ } finally {
+ try {
+ if (removed) {
+ tm.commit();
+ if (log.isTraceEnabled()) {
+ log.trace("Lock: {} removed for index: {} ", new Object[] { lockName, indexName });
+ }
+ } else {
+ tm.rollback();
+ }
+ } catch (Exception e) {
+ throw new CacheException("Unable to release lock!", e);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLocked() {
+ boolean locked = false;
+ synchronized (cache) {
+ Transaction tx = null;
+ try {
+ // if there is an ongoing transaction we need to suspend it
+ if ((tx = tm.getTransaction()) != null) {
+ tm.suspend();
+ }
+ locked = cache.containsKey(new FileCacheKey(indexName, lockName, true));
+ } catch (Exception e) {
+ log.error("Error in suspending transaction", e);
+ } finally {
+ if (tx != null) {
+ try {
+ tm.resume(tx);
+ } catch (Exception e) {
+ throw new CacheException("Unable to resume suspended transaction " + tx, e);
+ }
+ }
+ }
+ }
+ return locked;
+ }
+ }
+
+}
Property changes on: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java (rev 0)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,124 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.util.Random;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.DateTools;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.SerialMergeScheduler;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.LockObtainFailedException;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.infinispan.test.fwk.TestCacheManagerFactory;
+import org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup;
+import org.infinispan.config.Configuration;
+import org.infinispan.manager.CacheManager;
+
+public abstract class CacheTestSupport {
+
+ private static final Log log = LogFactory.getLog(CacheTestSupport.class);
+
+ protected static CacheManager createTestCacheManager() {
+ return TestCacheManagerFactory.createClusteredCacheManager( createTestConfiguration() );
+ }
+
+ protected static Configuration createTestConfiguration() {
+ Configuration c = new Configuration();
+ c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+ c.setSyncReplTimeout(10000);
+ c.setLockAcquisitionTimeout(10000);
+ c.setUseLockStriping(false);
+ c.setSyncCommitPhase(true);
+ c.setSyncRollbackPhase(true);
+ c.setTransactionManagerLookupClass(JBossStandaloneJTAManagerLookup.class.getName());
+ c.setDeadlockDetectionSpinDuration( 10000 );
+ return c;
+ }
+
+ protected static File createDummyDocToIndex(String fileName, int sz) throws Exception {
+ File dummyDocToIndex = new File(fileName);
+ if (dummyDocToIndex.exists()) {
+ dummyDocToIndex.delete();
+ }
+ dummyDocToIndex.createNewFile();
+ Random r = new Random();
+ FileWriter fw = new FileWriter(dummyDocToIndex);
+ for (int i = 0; i < sz; i++) {
+ fw.write(Integer.toHexString(r.nextInt(16)));
+ }
+ fw.close();
+ dummyDocToIndex.deleteOnExit();
+ return dummyDocToIndex;
+ }
+
+ protected static void doWriteOperation(Directory d, File document) throws Exception {
+ // this is a write
+ IndexWriter writer = null;
+ try {
+ writer = new IndexWriter(d, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
+ writer.setMergeScheduler(new SerialMergeScheduler());
+ log.info("IndexWriter was constructed");
+
+ Document doc = new Document();
+ doc.add(new Field("path", document.getPath(), Field.Store.YES, Field.Index.NOT_ANALYZED));
+ doc.add(new Field("modified", DateTools.timeToString(document.lastModified(), DateTools.Resolution.MINUTE),
+ Field.Store.YES, Field.Index.NOT_ANALYZED));
+ doc.add(new Field("contents", new FileReader(document)));
+ doc.add(new Field("info", "good", Field.Store.YES, Field.Index.ANALYZED));
+
+ writer.addDocument(doc);
+ } catch (LockObtainFailedException lofe) {
+ // can happen
+ } finally {
+ if (writer != null) {
+ writer.close();
+ log.info("IndexWriter was closed");
+ }
+ }
+ }
+
+ protected static void doReadOperation(Directory d) throws Exception {
+ IndexSearcher search = null;
+ try {
+ // this is a read
+ search = new IndexSearcher(d);
+ // dummy query that probably won't return anything
+ QueryParser qp = new QueryParser("path", new StandardAnalyzer());
+ search.search(qp.parse("good"), null, 1);
+ } finally {
+ if (search != null) {
+ search.close();
+ }
+ }
+ }
+
+}
Property changes on: trunk/lucene-directory/src/test/java/org/infinispan/lucene/CacheTestSupport.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanCacheEntryListenerTest.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanCacheEntryListenerTest.java (rev 0)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanCacheEntryListenerTest.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.infinispan.Cache;
+import org.infinispan.manager.CacheManager;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lukasz Moren
+ * @author Sanne Grinovero
+ */
+ at Test(groups = "functional", testName = "lucene.InfinispanCacheEntryListenerTest")
+public class InfinispanCacheEntryListenerTest {
+
+ Cache<CacheKey, Object> cache;
+ CacheManager cm;
+
+ public void testCacheEntryCreatedListener() {
+ final FileListCacheKey fileListKey = new FileListCacheKey( "index" );
+
+ //add some data
+ cache.put( fileListKey, Collections.synchronizedMap( new HashMap<String, String>() ) );
+ cache.addListener( new InfinispanCacheEntryListener( "index" ) );
+
+ final FileCacheKey key1 = new FileCacheKey( "index", "Hello.txt" );
+ cache.put( key1, new FileMetadata() );
+ cache.put( new ChunkCacheKey( "index", "Chunk.txt", 0 ), new byte[15] );
+ cache.put( new FileCacheKey( "index", "write.lock", true ), "");
+
+ final FileCacheKey key2 = new FileCacheKey( "index", "World.txt" );
+ cache.put( key2, new FileMetadata() );
+
+ final FileCacheKey key3 = new FileCacheKey( "index2", "Other.txt" );
+ cache.put( key3, new FileMetadata() );
+
+ //check if cache listener properly added file names to the list
+ Map map = ( Map ) cache.get( fileListKey );
+
+ assert map.containsKey( "Hello.txt" );
+ assert ! map.containsKey( "Chunk.txt" );
+ assert ! map.containsKey( "write.lock" );
+ assert map.containsKey( "World.txt" );
+ assert ! map.containsKey( "Other.txt" );
+
+ cache.remove( key1 );
+ cache.remove( key2 );
+ cache.remove( key3 );
+
+ //and properly removed file names from the list
+ map = ( Map ) cache.get( fileListKey );
+
+ assert ! map.containsKey( "Hello.txt" );
+ assert ! map.containsKey( "World.txt" );
+ assert ! map.containsKey( "Other.txt" );
+ }
+
+ @BeforeTest
+ public void setUp() {
+ cm = CacheTestSupport.createTestCacheManager();
+ cache = cm.getCache();
+ }
+
+ @AfterTest
+ public void tearDown() {
+ if ( cache != null ) {
+ cache.stop();
+ }
+ if ( cm != null ) {
+ cm.stop();
+ }
+ }
+}
Property changes on: trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanCacheEntryListenerTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryIOTest.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryIOTest.java (rev 0)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryIOTest.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,258 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.IndexOutput;
+import org.infinispan.Cache;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lukasz Moren
+ * @author Sanne Grinovero
+ */
+ at Test(groups = "functional", testName = "lucene.InfinispanDirectoryIOTest")
+public class InfinispanDirectoryIOTest {
+
+ public void testReadChunks() throws Exception {
+ final int BUFFER_SIZE = 64;
+
+ Cache<CacheKey, Object> cache = CacheTestSupport.createTestCacheManager().getCache();
+ InfinispanDirectory dir = new InfinispanDirectory(cache, "index", BUFFER_SIZE);
+
+ // create file headers
+ FileMetadata file1 = new FileMetadata();
+ CacheKey key1 = new FileCacheKey("index", "Hello.txt");
+ cache.put(key1, file1);
+
+ FileMetadata file2 = new FileMetadata();
+ CacheKey key2 = new FileCacheKey("index", "World.txt");
+ cache.put(key2, file2);
+
+ // byte array for Hello.txt
+ String helloText = "Hello world. This is some text.";
+ cache.put(new ChunkCacheKey("index", "Hello.txt", 0), helloText.getBytes());
+
+ // byte array for World.txt - should be in at least 2 chunks.
+ String worldText = "This String should contain more than sixty four characters but less than one hundred and twenty eight.";
+
+ byte[] buf = new byte[BUFFER_SIZE];
+ System.arraycopy(worldText.getBytes(), 0, buf, 0, BUFFER_SIZE);
+ cache.put(new ChunkCacheKey("index", "World.txt", 0), buf);
+
+ String part1 = new String(buf);
+ buf = new byte[BUFFER_SIZE];
+ System.arraycopy(worldText.getBytes(), BUFFER_SIZE, buf, 0, worldText.length() - BUFFER_SIZE);
+ cache.put(new ChunkCacheKey("index", "World.txt", 1), buf);
+ String part2 = new String(buf);
+
+ // make sure the generated bytes do add up!
+ assert worldText.equals( part1 + part2.trim() );
+
+ file1.setSize(helloText.length());
+ file2.setSize(worldText.length());
+
+ Set<String> s = new HashSet<String>();
+ s.add("Hello.txt");
+ s.add("World.txt");
+ Set other = new HashSet(Arrays.asList(dir.list()));
+
+ // ok, file listing works.
+ assert s.equals(other);
+
+ IndexInput ii = dir.openInput("Hello.txt");
+
+ assert ii.length() == helloText.length();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ for (int i = 0; i < ii.length(); i++) {
+ baos.write(ii.readByte());
+ }
+
+ assert new String(baos.toByteArray()).equals(helloText);
+
+ ii = dir.openInput("World.txt");
+
+ assert ii.length() == worldText.length();
+
+ baos = new ByteArrayOutputStream();
+
+ for (int i = 0; i < ii.length(); i++) {
+ baos.write(ii.readByte());
+ }
+
+ assert new String(baos.toByteArray()).equals(worldText);
+
+ // now with buffered reading
+
+ ii = dir.openInput("Hello.txt");
+
+ assert ii.length() == helloText.length();
+
+ baos = new ByteArrayOutputStream();
+
+ long toRead = ii.length();
+ while (toRead > 0) {
+ buf = new byte[19]; // suitably arbitrary
+ int bytesRead = (int) Math.min(toRead, 19);
+ ii.readBytes(buf, 0, bytesRead);
+ toRead = toRead - bytesRead;
+ baos.write(buf, 0, bytesRead);
+ }
+
+ assert new String(baos.toByteArray()).equals(helloText);
+
+ ii = dir.openInput("World.txt");
+
+ assert ii.length() == worldText.length();
+
+ baos = new ByteArrayOutputStream();
+
+ toRead = ii.length();
+ while (toRead > 0) {
+ buf = new byte[19]; // suitably arbitrary
+ int bytesRead = (int) Math.min(toRead, 19);
+ ii.readBytes(buf, 0, bytesRead);
+ toRead = toRead - bytesRead;
+ baos.write(buf, 0, bytesRead);
+ }
+
+ assert new String(baos.toByteArray()).equals(worldText);
+
+ dir.deleteFile("Hello.txt");
+ assert null == cache.get(new FileCacheKey("index", "Hello.txt"));
+ assert null == cache.get(new ChunkCacheKey("index", "Hello.txt", 0));
+
+ Object ob1 = cache.get(new FileCacheKey("index", "World.txt"));
+ Object ob2 = cache.get(new ChunkCacheKey("index", "World.txt", 0));
+ Object ob3 = cache.get(new ChunkCacheKey("index", "World.txt", 1));
+
+ dir.renameFile("World.txt", "HelloWorld.txt");
+ assert null == cache.get(new FileCacheKey("index", "Hello.txt"));
+ assert null == cache.get(new ChunkCacheKey("index", "Hello.txt", 0));
+ assert null == cache.get(new ChunkCacheKey("index", "Hello.txt", 1));
+
+ assert cache.get(new FileCacheKey("index", "HelloWorld.txt")).equals(ob1);
+ assert cache.get(new ChunkCacheKey("index", "HelloWorld.txt", 0)).equals(ob2);
+ assert cache.get(new ChunkCacheKey("index", "HelloWorld.txt", 1)).equals(ob3);
+
+ // test that contents survive a move
+ ii = dir.openInput("HelloWorld.txt");
+
+ assert ii.length() == worldText.length();
+
+ baos = new ByteArrayOutputStream();
+
+ toRead = ii.length();
+ while (toRead > 0) {
+ buf = new byte[19]; // suitably arbitrary
+ int bytesRead = (int) Math.min(toRead, 19);
+ ii.readBytes(buf, 0, bytesRead);
+ toRead = toRead - bytesRead;
+ baos.write(buf, 0, bytesRead);
+ }
+
+ assert new String(baos.toByteArray()).equals(worldText);
+
+ cache.getCacheManager().stop();
+ dir.close();
+
+ }
+
+ public void testWriteChunks() throws Exception {
+ final int BUFFER_SIZE = 64;
+
+ Cache<CacheKey, Object> cache = CacheTestSupport.createTestCacheManager().getCache();
+ InfinispanDirectory dir = new InfinispanDirectory(cache, "index", BUFFER_SIZE);
+
+ IndexOutput io = dir.createOutput("MyNewFile.txt");
+
+ io.writeByte((byte) 66);
+ io.writeByte((byte) 69);
+
+ io.close();
+
+ assert dir.fileExists("MyNewFile.txt");
+ assert null!=cache.get(new ChunkCacheKey("index", "MyNewFile.txt", 0));
+
+ // test contents by reading:
+ byte[] buf = new byte[9];
+ IndexInput ii = dir.openInput("MyNewFile.txt");
+ ii.readBytes(buf, 0, (int) ii.length());
+
+ assert new String(new byte[] { 66, 69 }).equals(new String(buf).trim());
+
+ String testText = "This is some rubbish again that will span more than one chunk - one hopes. Who knows, maybe even three or four chunks.";
+ io.seek(0);
+ io.writeBytes(testText.getBytes(), 0, testText.length());
+ io.close();
+ // now compare.
+ byte[] chunk1 = (byte[]) cache.get(new ChunkCacheKey("index", "MyNewFile.txt", 0));
+ byte[] chunk2 = (byte[]) cache.get(new ChunkCacheKey("index", "MyNewFile.txt", 1));
+ assert null!=chunk1;
+ assert null!=chunk2;
+
+ assert testText.equals(new String(chunk1) + new String(chunk2).trim());
+
+ cache.getCacheManager().stop();
+ dir.close();
+ }
+
+ public void testWriteChunksDefaultChunks() throws Exception {
+ Cache<CacheKey, Object> cache = CacheTestSupport.createTestCacheManager().getCache();
+ InfinispanDirectory dir = new InfinispanDirectory(cache, "index");
+
+ String testText = "This is some rubbish";
+ byte[] testTextAsBytes = testText.getBytes();
+
+ IndexOutput io = dir.createOutput("MyNewFile.txt");
+
+ io.writeByte((byte) 1);
+ io.writeByte((byte) 2);
+ io.writeByte((byte) 3);
+ io.writeBytes(testTextAsBytes, testTextAsBytes.length);
+ io.close();
+
+ assert null!=cache.get(new FileCacheKey("index", "MyNewFile.txt"));
+ assert null!=cache.get(new ChunkCacheKey("index", "MyNewFile.txt", 0));
+
+ // test contents by reading:
+ IndexInput ii = dir.openInput("MyNewFile.txt");
+ assert ii.readByte()== 1;
+ assert ii.readByte()== 2;
+ assert ii.readByte()== 3;
+ byte[] buf = new byte[32];
+
+ ii.readBytes(buf, 0, testTextAsBytes.length);
+
+ assert testText.equals(new String(buf).trim());
+
+ cache.getCacheManager().stop();
+ dir.close();
+ }
+}
Property changes on: trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryIOTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryStressTest.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryStressTest.java (rev 0)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryStressTest.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,166 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.Hits;
+import org.infinispan.Cache;
+import org.infinispan.manager.CacheManager;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lukasz Moren
+ * @author Sanne Grinovero
+ */
+ at SuppressWarnings("deprecation")
+ at Test(groups = "profiling", testName = "lucene.InfinispanDirectoryTest")
+public class InfinispanDirectoryStressTest {
+
+ private static final Log log = LogFactory.getLog(InfinispanDirectoryStressTest.class);
+
+ public static final int THREADS_NUM = 50;
+ public static final int TURNS_NUM = 300;
+
+ private AtomicInteger writeCount = new AtomicInteger(0);
+
+ public void testInfinispanDirectory() throws Exception {
+ final int OPERATIONS = 100;
+ CacheManager cacheManager = CacheTestSupport.createTestCacheManager();
+ Cache<CacheKey, Object> cache = cacheManager.getCache();
+ Directory directory = new InfinispanDirectory(cache, "indexName");
+ File document = CacheTestSupport.createDummyDocToIndex("document.lucene", 10000);
+
+ for (int i = 0; i < OPERATIONS; i++) {
+ CacheTestSupport.doWriteOperation(directory, document);
+ CacheTestSupport.doReadOperation(directory);
+ }
+
+ IndexSearcher search = new IndexSearcher(directory);
+ Term t = new Term("info", "good");
+ Query query = new TermQuery(t);
+ Hits hits = search.search(query);
+
+ assert OPERATIONS == hits.length();
+
+ directory.close();
+ cacheManager.stop();
+ }
+
+ public void testDirectoryWithMultipleThreads() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ List<InfinispanDirectoryThread> threads = new ArrayList<InfinispanDirectoryThread>();
+ Cache<CacheKey, Object> cache = CacheTestSupport.createTestCacheManager().getCache();
+ Cache<CacheKey, Object> cache2 = CacheTestSupport.createTestCacheManager().getCache(); // dummy cache, to force replication
+ Directory directory = new InfinispanDirectory(cache, "indexName");
+
+ IndexWriter.MaxFieldLength fieldLength = new IndexWriter.MaxFieldLength(IndexWriter.DEFAULT_MAX_FIELD_LENGTH);
+ IndexWriter iw = new IndexWriter(directory, new StandardAnalyzer(), true, fieldLength);
+ iw.close();
+
+ // create first writing thread
+ InfinispanDirectoryThread tr = new InfinispanDirectoryThread(latch, directory, true);
+ threads.add(tr);
+ tr.start();
+ // others reading threads
+ for (int i = 0; i < THREADS_NUM - 1; i++) {
+ InfinispanDirectoryThread thread = new InfinispanDirectoryThread(latch, directory, false);
+ threads.add(thread);
+ thread.start();
+ }
+
+ latch.countDown();
+
+ for (InfinispanDirectoryThread thread : threads) {
+ thread.join();
+ }
+
+ for (InfinispanDirectoryThread thread : threads) {
+ if (thread.e != null) {
+ log.error("Exception was catched during the test: ", thread.e);
+ assert false : "Exception during test in parallel thread";
+ }
+ }
+
+ IndexSearcher search = new IndexSearcher(directory);
+ Term t = new Term("info", "good");
+ Query query = new TermQuery(t);
+ Hits hits = search.search(query);
+
+ assert writeCount.get() == hits.length();
+
+ search.close();
+ directory.close();
+ cache.getCacheManager().stop();
+ cache2.getCacheManager().stop();
+ }
+
+ class InfinispanDirectoryThread extends Thread {
+ Exception e;
+ CountDownLatch latch;
+ File document;
+ Directory dir;
+ boolean isWritingThread = false;
+
+ protected InfinispanDirectoryThread(CountDownLatch latch, Directory dir, boolean isWritingThread)
+ throws Exception {
+ this.latch = latch;
+ this.dir = dir;
+ this.isWritingThread = isWritingThread;
+ document = CacheTestSupport.createDummyDocToIndex("document.lucene", 10000);
+ }
+
+ @Override
+ public void run() {
+ try {
+ latch.await();
+ for (int i = 0; i < TURNS_NUM; i++) {
+
+ if (!isWritingThread) {
+ CacheTestSupport.doReadOperation(dir);
+ } else {
+ writeCount.incrementAndGet();
+ CacheTestSupport.doWriteOperation(dir, document);
+ }
+ }
+
+ } catch (Exception ex) {
+ log.error("Error", ex);
+ e = ex;
+ }
+ }
+ }
+
+}
Property changes on: trunk/lucene-directory/src/test/java/org/infinispan/lucene/InfinispanDirectoryStressTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Added: trunk/lucene-directory/src/test/java/org/infinispan/lucene/SimpleLuceneTest.java
===================================================================
--- trunk/lucene-directory/src/test/java/org/infinispan/lucene/SimpleLuceneTest.java (rev 0)
+++ trunk/lucene-directory/src/test/java/org/infinispan/lucene/SimpleLuceneTest.java 2009-10-15 23:59:00 UTC (rev 957)
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.lucene;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.infinispan.config.Configuration;
+import org.infinispan.test.MultipleCacheManagersTest;
+import org.testng.annotations.Test;
+
+/**
+ * SimpleLuceneTest tests the basic functionality of the Lucene Directory
+ * on Infinispan: what is inserted in one node should be able to be found in
+ * a second node.
+ *
+ * @author Sanne Grinovero
+ * @since 4.0
+ */
+ at Test(groups = "functional", testName = "lucene.SimpleLuceneTest")
+public class SimpleLuceneTest extends MultipleCacheManagersTest {
+
+ private static final StandardAnalyzer analyzer = new StandardAnalyzer(new String[0]);
+
+ @Override
+ protected void createCacheManagers() throws Throwable {
+ Configuration configuration = CacheTestSupport.createTestConfiguration();
+ createClusteredCaches(2, "lucene", configuration);
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testIndexWritingAndFinding() throws IOException {
+ Directory dirA = new InfinispanDirectory(cache(0, "lucene"), "indexName");
+ Directory dirB = new InfinispanDirectory(cache(1, "lucene"), "indexName");
+ writeTextToIndex(dirA, 0, "hi from node A");
+ assertTextIsFoundInIds(dirA, "hi", 0);
+ assertTextIsFoundInIds(dirB, "hi", 0);
+ writeTextToIndex(dirB, 1, "hello node A, how are you?");
+ assertTextIsFoundInIds(dirA, "hello", 1);
+ assertTextIsFoundInIds(dirB, "hello", 1);
+ assertTextIsFoundInIds(dirA, "node", 1, 0); // node is keyword in both documents id=0 and id=1
+ assertTextIsFoundInIds(dirB, "node", 1, 0);
+ removeByTerm(dirA, "from");
+ assertTextIsFoundInIds(dirB, "node", 1);
+ }
+
+ /**
+ * Used in test to remove all documents containing some term
+ *
+ * @param dir The Directory containing the Index to verify
+ * @param string
+ */
+ private void removeByTerm(Directory dir, String term) throws IOException {
+ IndexWriter iw = new IndexWriter(dir, analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
+ iw.deleteDocuments(new Term("body", term));
+ iw.commit();
+ iw.close();
+ }
+
+ /**
+ * Used in test to verify an Index
+ *
+ * @param dir The Directory containing the Index to verify
+ * @param term a single Term (after analysis) to be searched for
+ * @param validDocumentIds The list of document identifiers which should contain the searched-for term
+ * @throws IOException
+ */
+ private void assertTextIsFoundInIds(Directory dir, String term, Integer... validDocumentIds) throws IOException {
+ int expectedResults = validDocumentIds.length;
+ Set<Integer> expectedDocumendIds = new HashSet<Integer>(Arrays.asList(validDocumentIds));
+ IndexSearcher searcher = new IndexSearcher(dir);
+ Query query = new TermQuery(new Term("body", term));
+ TopDocs docs = searcher.search(query, null, expectedResults + 1);
+ assert docs.totalHits == expectedResults;
+ for (ScoreDoc scoreDoc : docs.scoreDocs) {
+ int docId = scoreDoc.doc;
+ Document document = searcher.doc(docId);
+ String idString = document.get("id");
+ assert idString != null;
+ Integer idFoundElement = Integer.valueOf(idString);
+ assert expectedDocumendIds.contains(idFoundElement);
+ }
+ searcher.close();
+ }
+
+ /**
+ * Used in test to add a new Document to an Index; two fields are created: id and body
+ *
+ * @param dir The Directory containing the Index to modify
+ * @param id a sequential number to identify this document (id field)
+ * @param text Some text to add to the body field
+ * @throws IOException
+ */
+ private void writeTextToIndex(Directory dir, int id, String text) throws IOException {
+ IndexWriter iw = new IndexWriter(dir, analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
+ Document doc = new Document();
+ doc.add(new Field("id", String.valueOf(id), Field.Store.YES, Field.Index.NOT_ANALYZED));
+ doc.add(new Field("body", text, Field.Store.NO, Field.Index.ANALYZED));
+ iw.addDocument(doc);
+ iw.commit();
+ iw.close();
+ }
+
+}
Property changes on: trunk/lucene-directory/src/test/java/org/infinispan/lucene/SimpleLuceneTest.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
More information about the infinispan-commits
mailing list