/** * Invoked during commit processing to merge down the write set from each index isolated by this * transactions onto the corresponding unisolated index on the database. This method invoked iff a * transaction has successfully prepared and hence is known to have validated successfully. The * default implementation is a NOP. * * @param revisionTime * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/675" >Flush indices in parallel * during checkpoint to reduce IO latency</a> */ protected void mergeOntoGlobalState(final long revisionTime) { this.revisionTime = revisionTime; // Create tasks to checkpoint the indices. final List<Callable<Void>> tasks = new LinkedList<Callable<Void>>(); { final Iterator<Map.Entry<String, ILocalBTreeView>> itr = indices.entrySet().iterator(); while (itr.hasNext()) { final Map.Entry<String, ILocalBTreeView> entry = itr.next(); final String name = entry.getKey(); final IsolatedFusedView isolated = (IsolatedFusedView) entry.getValue(); tasks.add(new CheckpointIndexTask(name, isolated)); } } /* * Submit checkpoint tasks. * * Note: Method blocks until all tasks are done. */ final List<Future<Void>> futures; try { futures = resourceManager.getLiveJournal().getExecutorService().invokeAll(tasks); } catch (InterruptedException ex) { throw new RuntimeException(ex); } /* * Check Futures for errors. * * Note: Per above, all futures are known to be done. */ for (Future<Void> f : futures) { try { f.get(); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e); } } }
/** * @todo This might need to be a full {@link Journal} using {@link BufferMode#Temporary} in order * to have concurrency control for the isolated named indices. This would let us leverage the * existing {@link WriteExecutorService} for handling concurrent operations within a * transaction on the same named _isolated_ resource. There are a lot of issues here, * including the level of concurrency expected for transactions. Also, note that the write set * of the tx is not restart safe, we never force writes to disk, etc. Those are good fits for * the {@link BufferMode#Temporary} {@link BufferMode}. However, it might be nice to do * without having a {@link WriteExecutorService} per transaction, e.g., by placing the named * indices for a transaction within a namespace for that tx. * @todo Rather than creating a distinct {@link TemporaryStore} for each tx and then closing and * deleting the store when the tx completes, just use the temporary store factory. Once there * are no more tx's using a given temporary store it will automatically be finalized and * deleted. However, it is important that we namespace the indices so that different * transactions do not see one another's data. * <p>We can do this just as easily with {@link BufferMode#Temporary}, but {@link * IIndexStore#getTempStore()} would have to be modified. However, that would give us more * concurrency control in the tmp stores and we might need that for concurrent access to named * indices (see above). */ private IRawStore getTemporaryStore() { return resourceManager.getLiveJournal().getTempStore(); // assert lock.isHeldByCurrentThread(); // // if (tmpStore == null) { // // final int offsetBits = resourceManager.getLiveJournal() // .getOffsetBits(); // // tmpStore = new TemporaryRawStore(offsetBits); // // } // // return tmpStore; }