| | |
| | | } |
| | | else |
| | | { |
| | | doRebuildIndexes(); |
| | | rebuildIndexes0(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | |
| | | }); |
| | | } |
| | | |
| | | private void doRebuildIndexes() throws Exception |
| | | private void rebuildIndexes0() throws Exception |
| | | { |
| | | final long startTime = System.currentTimeMillis(); |
| | | final Storage storage = rootContainer.getStorage(); |
| | |
| | | { |
| | | for (IndexManager indexMgr : indexMgrs) |
| | | { |
| | | // avoid threading issues by allocating one writeable storage per thread |
| | | // DB transactions are generally tied to a single thread |
| | | WriteableTransaction txn = this.rootContainer.getStorage().getWriteableTransaction(); |
| | | futures.add(dbService.submit(new IndexDBWriteTask(indexMgr, txn, permits, buffers, readAheadSize))); |
| | | futures.add(dbService.submit( |
| | | new IndexDBWriteTask(rootContainer.getStorage(), indexMgr, permits, buffers, readAheadSize))); |
| | | } |
| | | } |
| | | |
| | |
| | | isCanceled = true; |
| | | throw e; |
| | | } |
| | | finally |
| | | { |
| | | txn.close(); |
| | | } |
| | | } |
| | | |
| | | void processEntry(WriteableTransaction txn, Entry entry, Suffix suffix) |
| | |
| | | isCanceled = true; |
| | | throw e; |
| | | } |
| | | finally |
| | | { |
| | | txn.close(); |
| | | } |
| | | } |
| | | |
| | | void processEntry(WriteableTransaction txn, Entry entry, EntryID entryID, Suffix suffix) |
| | |
| | | */ |
| | | private final class IndexDBWriteTask implements Callable<Void> |
| | | { |
| | | private final Storage storage; |
| | | private final IndexManager indexMgr; |
| | | private final int cacheSize; |
| | | /** indexID => DNState map */ |
| | |
| | | private int nextBufferID; |
| | | private int ownedPermits; |
| | | private volatile boolean isRunning; |
| | | private final WriteableTransaction txn; |
| | | |
| | | /** |
| | | * Creates a new index DB writer. |
| | | * |
| | | * @param indexMgr |
| | | * The index manager. |
| | | * @param txn |
| | | * The database transaction |
| | | * @param storage |
| | | * Where to store data |
| | | * @param permits |
| | | * The semaphore used for restricting the number of buffer allocations. |
| | | * @param maxPermits |
| | |
| | | * @param cacheSize |
| | | * The buffer cache size. |
| | | */ |
| | | public IndexDBWriteTask(IndexManager indexMgr, WriteableTransaction txn, Semaphore permits, int maxPermits, |
| | | int cacheSize) |
| | | public IndexDBWriteTask(Storage storage, IndexManager indexMgr, Semaphore permits, int maxPermits, int cacheSize) |
| | | { |
| | | this.storage = storage; |
| | | this.indexMgr = indexMgr; |
| | | this.txn = txn; |
| | | this.permits = permits; |
| | | this.maxPermits = maxPermits; |
| | | this.cacheSize = cacheSize; |
| | |
| | | return buffers; |
| | | } |
| | | |
| | | /** |
| | | * Finishes this task. |
| | | */ |
| | | public void endWriteTask() |
| | | /** Finishes this task. */ |
| | | private void endWriteTask(WriteableTransaction txn) |
| | | { |
| | | isRunning = false; |
| | | |
| | |
| | | { |
| | | for (DNState dnState : dnStateMap.values()) |
| | | { |
| | | dnState.flush(); |
| | | dnState.flush(txn); |
| | | } |
| | | if (!isCanceled) |
| | | { |
| | |
| | | } |
| | | finally |
| | | { |
| | | close(bufferFile, bufferIndexFile, txn); |
| | | close(bufferFile, bufferIndexFile); |
| | | |
| | | indexMgr.getBufferFile().delete(); |
| | | indexMgr.getBufferIndexFile().delete(); |
| | |
| | | @Override |
| | | public Void call() throws Exception |
| | | { |
| | | storage.write(new WriteOperation() |
| | | { |
| | | @Override |
| | | public void run(WriteableTransaction txn) throws Exception |
| | | { |
| | | call0(txn); |
| | | } |
| | | }); |
| | | return null; |
| | | } |
| | | |
| | | private void call0(WriteableTransaction txn) throws Exception |
| | | { |
| | | if (isCanceled) |
| | | { |
| | | return null; |
| | | return; |
| | | } |
| | | |
| | | ImportIDSet insertIDSet = null; |
| | |
| | | { |
| | | if (isCanceled) |
| | | { |
| | | return null; |
| | | return; |
| | | } |
| | | |
| | | while (!bufferSet.isEmpty()) |
| | |
| | | { |
| | | if (previousRecord != null) |
| | | { |
| | | addToDB(previousRecord.getIndexID(), insertIDSet, deleteIDSet); |
| | | addToDB(txn, previousRecord.getIndexID(), insertIDSet, deleteIDSet); |
| | | } |
| | | |
| | | // this is a new record |
| | |
| | | |
| | | if (previousRecord != null) |
| | | { |
| | | addToDB(previousRecord.getIndexID(), insertIDSet, deleteIDSet); |
| | | addToDB(txn, previousRecord.getIndexID(), insertIDSet, deleteIDSet); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | } |
| | | finally |
| | | { |
| | | endWriteTask(); |
| | | endWriteTask(txn); |
| | | } |
| | | } |
| | | |
| | |
| | | return new ImportIDSet(record.getKey(), newDefinedSet(), index.getIndexEntryLimit(), index.getMaintainCount()); |
| | | } |
| | | |
| | | private void addToDB(int indexID, ImportIDSet insertSet, ImportIDSet deleteSet) throws DirectoryException |
| | | private void addToDB(WriteableTransaction txn, int indexID, ImportIDSet insertSet, ImportIDSet deleteSet) |
| | | throws DirectoryException |
| | | { |
| | | keyCount.incrementAndGet(); |
| | | if (indexMgr.isDN2ID()) |
| | | { |
| | | addDN2ID(indexID, insertSet); |
| | | addDN2ID(txn, indexID, insertSet); |
| | | } |
| | | else |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private void addDN2ID(int indexID, ImportIDSet idSet) throws DirectoryException |
| | | private void addDN2ID(WriteableTransaction txn, int indexID, ImportIDSet idSet) throws DirectoryException |
| | | { |
| | | DNState dnState = dnStateMap.get(indexID); |
| | | if (dnState == null) |
| | |
| | | } |
| | | if (dnState.checkParent(txn, idSet)) |
| | | { |
| | | dnState.writeToDN2ID(idSet); |
| | | dnState.writeToDN2ID(txn, idSet); |
| | | } |
| | | } |
| | | |
| | |
| | | return true; |
| | | } |
| | | |
| | | private void id2child(EntryID childID) throws DirectoryException |
| | | private void id2child(WriteableTransaction txn, EntryID childID) throws DirectoryException |
| | | { |
| | | if (parentID == null) |
| | | { |
| | |
| | | getId2childtreeImportIDSet().addEntryID(childID); |
| | | if (id2childTree.size() > DN_STATE_CACHE_SIZE) |
| | | { |
| | | flushMapToDB(id2childTree, entryContainer.getID2Children(), true); |
| | | flushToDB(txn, id2childTree.values(), entryContainer.getID2Children(), true); |
| | | } |
| | | } |
| | | |
| | |
| | | return idSet; |
| | | } |
| | | |
| | | private void id2SubTree(ReadableTransaction txn, EntryID childID) throws DirectoryException |
| | | private void id2SubTree(WriteableTransaction txn, EntryID childID) throws DirectoryException |
| | | { |
| | | if (parentID == null) |
| | | { |
| | |
| | | } |
| | | if (id2subtreeTree.size() > DN_STATE_CACHE_SIZE) |
| | | { |
| | | flushMapToDB(id2subtreeTree, entryContainer.getID2Subtree(), true); |
| | | flushToDB(txn, id2subtreeTree.values(), entryContainer.getID2Subtree(), true); |
| | | } |
| | | } |
| | | |
| | |
| | | return idSet; |
| | | } |
| | | |
| | | public void writeToDN2ID(ImportIDSet idSet) throws DirectoryException |
| | | public void writeToDN2ID(WriteableTransaction txn, ImportIDSet idSet) throws DirectoryException |
| | | { |
| | | txn.put(dn2id, idSet.getKey(), entryID.toByteString()); |
| | | indexMgr.addTotDNCount(1); |
| | | if (parentDN != null) |
| | | { |
| | | id2child(entryID); |
| | | id2child(txn, entryID); |
| | | id2SubTree(txn, entryID); |
| | | } |
| | | } |
| | | |
| | | public void flush() |
| | | public void flush(WriteableTransaction txn) |
| | | { |
| | | flushMapToDB(id2childTree, entryContainer.getID2Children(), false); |
| | | flushMapToDB(id2subtreeTree, entryContainer.getID2Subtree(), false); |
| | | flushToDB(txn, id2childTree.values(), entryContainer.getID2Children(), false); |
| | | flushToDB(txn, id2subtreeTree.values(), entryContainer.getID2Subtree(), false); |
| | | } |
| | | |
| | | private void flushMapToDB(Map<ByteString, ImportIDSet> map, Index index, boolean clearMap) |
| | | private void flushToDB(WriteableTransaction txn, Collection<ImportIDSet> idSets, Index index, boolean clearIDSets) |
| | | { |
| | | for (ImportIDSet idSet : map.values()) |
| | | for (ImportIDSet idSet : idSets) |
| | | { |
| | | index.importPut(txn, idSet); |
| | | } |
| | | if (clearMap) |
| | | if (clearIDSets) |
| | | { |
| | | map.clear(); |
| | | idSets.clear(); |
| | | } |
| | | } |
| | | } |