/* * Copyright 2004-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.compass.needle.gigaspaces.store; import java.io.IOException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.j_spaces.core.IJSpace; import net.jini.core.lease.Lease; import org.apache.lucene.index.LuceneFileNames; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; import org.openspaces.core.GigaSpace; /** * GigaSpace Directory is a Lucene directory built on top of GigaSpaces. * * <p>The direcotry implementation uses {@link FileEntry} * as the meta data of a file written to the Space. And one or more {@link FileBucketEntry} * to hold the entry data. Note, the bucket size can eb controlled during index creation, but if connecting * to an existing index, the bucket index must be the same. * * @author kimchy */ public class GigaSpaceDirectory extends Directory { public static final int DEFAULT_BUCKET_SIZE = 20 * 1024; public static final int DEFAULT_FLUSH_RATE = 50; private IJSpace space; private String indexName; private int bucketSize = DEFAULT_BUCKET_SIZE; private int flushRate = DEFAULT_FLUSH_RATE; // we store an on going list of created index outputs since Lucene needs them // *before* it closes the index output. It calls fileExists in the middle. private Map<String, IndexOutput> onGoingIndexOutputs = new ConcurrentHashMap<String, IndexOutput>(); public GigaSpaceDirectory(GigaSpace gigaSpace, String indexName) { this(gigaSpace.getSpace(), indexName); } public GigaSpaceDirectory(IJSpace space, String indexName) { this(space, indexName, DEFAULT_BUCKET_SIZE); } public GigaSpaceDirectory(IJSpace space, String indexName, int bucketSize) { this(space, indexName, bucketSize, DEFAULT_FLUSH_RATE); } public GigaSpaceDirectory(IJSpace space, String indexName, int bucketSize, int flushRate) { this.space = space; this.indexName = indexName; this.bucketSize = bucketSize; this.flushRate = flushRate; setLockFactory(new GigaSpaceLockFactory(space, indexName)); } public void deleteContent() throws IOException { FileEntry fileEntry = new FileEntry(indexName, null); try { space.clear(fileEntry, null); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, null, "Delete failed", e); } FileBucketEntry fileBucketEntry = new FileBucketEntry(indexName, null); try { space.clear(fileBucketEntry, null); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, null, "Delete failed", e); } } Map<String, IndexOutput> getOnGoingIndexOutputs() { return onGoingIndexOutputs; } public IJSpace getSpace() { return space; } String getIndexName() { return indexName; } int getBucketSize() { return bucketSize; } int getFlushRate() { return flushRate; } public void deleteFile(String fileName) throws IOException { FileEntry fileEntry = new FileEntry(indexName, fileName); try { space.clear(fileEntry, null); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "Delete failed", e); } FileBucketEntry fileBucketEntry = new FileBucketEntry(indexName, fileName); try { space.clear(fileBucketEntry, null); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "Delete failed", e); } } public boolean fileExists(String fileName) throws IOException { if (onGoingIndexOutputs.containsKey(fileName)) { return true; } FileEntry fileEntry = new FileEntry(indexName, fileName); try { int count = space.count(fileEntry, null); return count > 0; } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "File exists failed", e); } } public long fileLength(String fileName) throws IOException { FileEntry fileEntryTemplate = new FileEntry(indexName, fileName); try { FileEntry fileEntry = (FileEntry) space.read(fileEntryTemplate, null, 0); if (fileEntry == null) { return 0; } return fileEntry.getSize(); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "File length failed", e); } } public long fileModified(String fileName) throws IOException { FileEntry fileEntryTemplate = new FileEntry(indexName, fileName); try { FileEntry fileEntry = (FileEntry) space.read(fileEntryTemplate, null, 0); if (fileEntry == null) { return 0; } return fileEntry.getLastModified(); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "File modified failed", e); } } public String[] list() throws IOException { FileEntry fileEntryTemplate = new FileEntry(indexName, null); try { Object[] results = space.readMultiple(fileEntryTemplate, null, Integer.MAX_VALUE); String[] retVal = new String[results.length]; for (int i = 0; i < results.length; i++) { retVal[i] = ((FileEntry) results[i]).getFileName(); } return retVal; } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, null, "File list failed", e); } } public void renameFile(String from, String to) throws IOException { // renameFile is not used within Lucene anymore throw new UnsupportedOperationException("rename file not supported with GigaSpace direcotry"); } public void touchFile(String fileName) throws IOException { FileEntry fileEntryTemplate = new FileEntry(indexName, fileName); try { FileEntry fileEntry = (FileEntry) space.take(fileEntryTemplate, null, 0); if (fileEntry == null) { fileEntry = new FileEntry(indexName, fileName, 0); } fileEntry.touch(); space.write(fileEntry, null, Lease.FOREVER); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "File touch failed", e); } } public IndexInput openInput(String fileName) throws IOException { FileEntry fileEntry = new FileEntry(indexName, fileName); try { fileEntry = (FileEntry) space.read(fileEntry, null, 0); } catch (Exception e) { throw new GigaSpaceDirectoryException(indexName, fileName, "File to read file entry", e); } if (fileEntry == null) { throw new GigaSpaceDirectoryException(indexName, fileName, "Failed to find file entry"); } return new GigaSpaceIndexInput(this, fileEntry); } public IndexOutput createOutput(String fileName) throws IOException { IndexOutput out; if (LuceneFileNames.isSegmentsFile(fileName)) { out = new FlushOnCloseGigaSpaceIndexOutput(this, fileName); } else { out = new GigaSpaceMemIndexOutput(this, fileName); } onGoingIndexOutputs.put(fileName, out); return out; } /** * Does nothing since an already constructed Space is passes to this * directory. */ public void close() throws IOException { } }