package org.eclipse.jdt.internal.core.index.impl; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.jdt.internal.core.index.*; | |
import org.eclipse.jdt.internal.core.search.Util; | |
import org.eclipse.jdt.internal.compiler.util.*; | |
import java.io.*; | |
import java.util.*; | |
/** | |
* This input is used for reading indexes saved using a BlocksIndexOutput. | |
*/ | |
public class BlocksIndexInput extends IndexInput { | |
public static final int CACHE_SIZE= 16; // Cache 16 blocks of 8K each, for a cache size of 128K | |
protected FileListBlock currentFileListBlock; | |
protected int currentFileListBlockNum; | |
protected int currentIndexBlockNum; | |
protected IndexBlock currentIndexBlock; | |
private RandomAccessFile raf; | |
protected File indexFile; | |
protected LRUCache blockCache; | |
protected boolean opened= false; | |
protected IndexSummary summary; | |
public BlocksIndexInput(File inputFile) { | |
this.indexFile= inputFile; | |
blockCache= new LRUCache(CACHE_SIZE); | |
} | |
/** | |
* @see IndexInput#clearCache | |
*/ | |
public void clearCache() { | |
blockCache= new LRUCache(CACHE_SIZE); | |
} | |
/** | |
* @see IndexInput#close | |
*/ | |
public void close() throws IOException { | |
if (opened) { | |
raf.close(); | |
summary= null; | |
opened= false; | |
} | |
} | |
/** | |
* @see IndexInput#getCurrentFile | |
*/ | |
public IndexedFile getCurrentFile() throws IOException { | |
if (!hasMoreFiles()) | |
return null; | |
IndexedFile file= null; | |
if ((file= currentFileListBlock.getFile(filePosition)) == null) { | |
currentFileListBlockNum= summary.getBlockNumForFileNum(filePosition); | |
currentFileListBlock= getFileListBlock(currentFileListBlockNum); | |
file= currentFileListBlock.getFile(filePosition); | |
} | |
return file; | |
} | |
/** | |
* Returns the entry corresponding to the given word. | |
*/ | |
protected WordEntry getEntry(char[] word) throws IOException { | |
int blockNum= summary.getBlockNumForWord(word); | |
if (blockNum == -1) return null; | |
IndexBlock block= getIndexBlock(blockNum); | |
return block.findExactEntry(word); | |
} | |
/** | |
* Returns the FileListBlock with the given number. | |
*/ | |
protected FileListBlock getFileListBlock(int blockNum) throws IOException { | |
Integer key= new Integer(blockNum); | |
Block block= (Block) blockCache.get(key); | |
if (block != null && block instanceof FileListBlock) | |
return (FileListBlock) block; | |
FileListBlock fileListBlock= new FileListBlock(IIndexConstants.BLOCK_SIZE); | |
fileListBlock.read(raf, blockNum); | |
blockCache.put(key, fileListBlock); | |
return fileListBlock; | |
} | |
/** | |
* Returns the IndexBlock (containing words) with the given number. | |
*/ | |
protected IndexBlock getIndexBlock(int blockNum) throws IOException { | |
Integer key= new Integer(blockNum); | |
Block block= (Block) blockCache.get(key); | |
if (block != null && block instanceof IndexBlock) | |
return (IndexBlock) block; | |
IndexBlock indexBlock= new GammaCompressedIndexBlock(IIndexConstants.BLOCK_SIZE); | |
indexBlock.read(raf, blockNum); | |
blockCache.put(key, indexBlock); | |
return indexBlock; | |
} | |
/** | |
* @see IndexInput#getIndexedFile | |
*/ | |
public IndexedFile getIndexedFile(int fileNum) throws IOException { | |
int blockNum= summary.getBlockNumForFileNum(fileNum); | |
if (blockNum == -1) | |
return null; | |
FileListBlock block= getFileListBlock(blockNum); | |
return block.getFile(fileNum); | |
} | |
/** | |
* @see IndexInput#getIndexedFile | |
*/ | |
public IndexedFile getIndexedFile(IDocument document) throws java.io.IOException { | |
setFirstFile(); | |
String name= document.getName(); | |
while (hasMoreFiles()) { | |
IndexedFile file= getCurrentFile(); | |
String path= file.getPath(); | |
if (path.equals(name)) | |
return file; | |
moveToNextFile(); | |
} | |
return null; | |
} | |
/** | |
* Returns the list of numbers of files containing the given word. | |
*/ | |
protected int[] getMatchingFileNumbers(char[] word) throws IOException { | |
int blockNum= summary.getBlockNumForWord(word); | |
if (blockNum == -1) | |
return new int[0]; | |
IndexBlock block= getIndexBlock(blockNum); | |
WordEntry entry= block.findExactEntry(word); | |
return entry == null ? new int[0] : entry.getRefs(); | |
} | |
/** | |
* @see IndexInput#getNumFiles | |
*/ | |
public int getNumFiles() { | |
return summary.getNumFiles(); | |
} | |
/** | |
* @see IndexInput#getNumWords | |
*/ | |
public int getNumWords() { | |
return summary.getNumWords(); | |
} | |
/** | |
* @see IndexInput#getSource | |
*/ | |
public Object getSource() { | |
return indexFile; | |
} | |
/** | |
* Initialises the blocksIndexInput | |
*/ | |
protected void init() throws IOException { | |
clearCache(); | |
setFirstFile(); | |
setFirstWord(); | |
} | |
/** | |
* @see IndexInput#moveToNextFile | |
*/ | |
public void moveToNextFile() throws IOException { | |
filePosition++; | |
} | |
/** | |
* @see IndexInput#moveToNextEntry | |
*/ | |
public void moveToNextWordEntry() throws IOException { | |
wordPosition++; | |
if (!hasMoreWords()) { | |
return; | |
} | |
//if end of the current block, we load the next one. | |
boolean endOfBlock= !currentIndexBlock.nextEntry(currentWordEntry); | |
if (endOfBlock) { | |
currentIndexBlock= getIndexBlock(++currentIndexBlockNum); | |
currentIndexBlock.nextEntry(currentWordEntry); | |
} | |
} | |
/** | |
* @see IndexInput#open | |
*/ | |
public void open() throws IOException { | |
if (!opened) { | |
raf= new SafeRandomAccessFile(indexFile, "r"/*nonNLS*/); | |
String sig= raf.readUTF(); | |
if (!sig.equals(IIndexConstants.SIGNATURE)) | |
throw new IOException(Util.bind("exception.wrongFormat"/*nonNLS*/)); | |
int summaryBlockNum= raf.readInt(); | |
raf.seek(summaryBlockNum * (long) IIndexConstants.BLOCK_SIZE); | |
summary= new IndexSummary(); | |
summary.read(raf); | |
init(); | |
opened= true; | |
} | |
} | |
/** | |
* @see IndexInput#query | |
*/ | |
public IQueryResult[] query(String word) throws IOException { | |
open(); | |
int[] fileNums= getMatchingFileNumbers(word.toCharArray()); | |
int size= fileNums.length; | |
IQueryResult[] files= new IQueryResult[size]; | |
for (int i= 0; i < size; ++i) { | |
files[i]= getIndexedFile(fileNums[i]); | |
} | |
return files; | |
} | |
/** | |
* If no prefix is provided in the pattern, then this operation will have to walk | |
* all the entries of the whole index. | |
*/ | |
public IEntryResult[] queryEntriesMatching(char[] pattern/*, boolean isCaseSensitive*/) throws IOException { | |
open(); | |
if (pattern == null || pattern.length == 0) return null; | |
int[] blockNums = null; | |
int firstStar = CharOperation.indexOf('*', pattern); | |
switch (firstStar){ | |
case -1 : | |
WordEntry entry = getEntry(pattern); | |
if (entry == null) return null; | |
return new IEntryResult[]{ new EntryResult(entry.getWord(), entry.getRefs()) }; | |
case 0 : | |
blockNums = summary.getAllBlockNums(); | |
break; | |
default : | |
char[] prefix = CharOperation.subarray(pattern, 0, firstStar); | |
blockNums = summary.getBlockNumsForPrefix(prefix); | |
} | |
if (blockNums == null || blockNums.length == 0) return null; | |
IEntryResult[] entries = new IEntryResult[5]; | |
int count = 0; | |
for (int i = 0, max = blockNums.length; i < max; i++) { | |
IndexBlock block = getIndexBlock(blockNums[i]); | |
block.reset(); | |
boolean found = false; | |
WordEntry entry = new WordEntry(); | |
while (block.nextEntry(entry)) { | |
if (CharOperation.match(entry.getWord(), pattern, true)) { | |
if (count == entries.length){ | |
System.arraycopy(entries, 0, entries = new IEntryResult[count*2], 0, count); | |
} | |
entries[count++] = new EntryResult(entry.getWord(), entry.getRefs()); | |
found = true; | |
} else { | |
if (found) break; | |
} | |
} | |
} | |
if (count != entries.length){ | |
System.arraycopy(entries, 0, entries = new IEntryResult[count], 0, count); | |
} | |
return entries; | |
} | |
public IEntryResult[] queryEntriesPrefixedBy(char[] prefix/*, boolean isCaseSensitive*/) throws IOException { | |
open(); | |
int blockLoc = summary.getFirstBlockLocationForPrefix(prefix); | |
if (blockLoc < 0) return null; | |
IEntryResult[] entries = new IEntryResult[5]; | |
int count = 0; | |
while(blockLoc >= 0){ | |
IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc)); | |
block.reset(); | |
boolean found = false; | |
WordEntry entry = new WordEntry(); | |
while (block.nextEntry(entry)) { | |
if (CharOperation.prefixEquals(prefix, entry.getWord()/*, isCaseSensitive*/)) { | |
if (count == entries.length){ | |
System.arraycopy(entries, 0, entries = new IEntryResult[count*2], 0, count); | |
} | |
entries[count++] = new EntryResult(entry.getWord(), entry.getRefs()); | |
found = true; | |
} else { | |
if (found) break; | |
} | |
} | |
/* consider next block ? */ | |
blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc); | |
} | |
if (count == 0) return null; | |
if (count != entries.length){ | |
System.arraycopy(entries, 0, entries = new IEntryResult[count], 0, count); | |
} | |
return entries; | |
} | |
public IQueryResult[] queryFilesReferringToPrefix(char[] prefix) throws IOException { | |
open(); | |
int blockLoc = summary.getFirstBlockLocationForPrefix(prefix); | |
if (blockLoc < 0) return null; | |
IEntryResult[] entries = new IEntryResult[5]; | |
// each filename must be returned already once | |
org.eclipse.jdt.internal.compiler.util.HashtableOfInt fileMatches = new org.eclipse.jdt.internal.compiler.util.HashtableOfInt(20); | |
int count = 0; | |
while(blockLoc >= 0){ | |
IndexBlock block = getIndexBlock(summary.getBlockNum(blockLoc)); | |
block.reset(); | |
boolean found = false; | |
WordEntry entry = new WordEntry(); | |
while (block.nextEntry(entry)) { | |
if (CharOperation.prefixEquals(prefix, entry.getWord()/*, isCaseSensitive*/)) { | |
int [] refs = entry.getRefs(); | |
for (int i = 0, max = refs.length; i < max; i++){ | |
int ref = refs[i]; | |
if (!fileMatches.containsKey(ref)){ | |
count++; | |
fileMatches.put(ref, getIndexedFile(ref)); | |
} | |
} | |
found = true; | |
} else { | |
if (found) break; | |
} | |
} | |
/* consider next block ? */ | |
blockLoc = summary.getNextBlockLocationForPrefix(prefix, blockLoc); | |
} | |
/* extract indexed files */ | |
IQueryResult[] files = new IQueryResult[count]; | |
Object[] indexedFiles = fileMatches.valueTable; | |
for (int i = 0, index = 0, max = indexedFiles.length; i < max; i++){ | |
IndexedFile indexedFile = (IndexedFile) indexedFiles[i]; | |
if (indexedFile != null){ | |
files[index++] = indexedFile; | |
} | |
} | |
return files; | |
} | |
/** | |
* @see IndexInput#query | |
*/ | |
public IQueryResult[] queryInDocumentNames(String word) throws IOException { | |
open(); | |
Vector matches= new Vector(); | |
setFirstFile(); | |
while (hasMoreFiles()) { | |
IndexedFile file= getCurrentFile(); | |
if (file.getPath().indexOf(word) != -1) | |
matches.addElement(file); | |
moveToNextFile(); | |
} | |
IQueryResult[] match= new IQueryResult[matches.size()]; | |
matches.copyInto(match); | |
return match; | |
} | |
/** | |
* @see IndexInput#setFirstFile | |
*/ | |
protected void setFirstFile() throws IOException { | |
filePosition= 1; | |
if (getNumFiles() > 0) { | |
currentFileListBlockNum= summary.getBlockNumForFileNum(1); | |
currentFileListBlock= getFileListBlock(currentFileListBlockNum); | |
} | |
} | |
/** | |
* @see IndexInput#setFirstWord | |
*/ | |
protected void setFirstWord() throws IOException { | |
wordPosition= 1; | |
if (getNumWords() > 0) { | |
currentIndexBlockNum= summary.getFirstWordBlockNum(); | |
currentIndexBlock= getIndexBlock(currentIndexBlockNum); | |
currentWordEntry= new WordEntry(); | |
currentIndexBlock.reset(); | |
currentIndexBlock.nextEntry(currentWordEntry); | |
} | |
} | |
} |