[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