private ThreadStart Updater <T1, T2>(AtomicReferenceArray <T1> lastBatches, System.Threading.CountdownEvent insertersDone, ReadWriteLock updateLock, ICollection <T2> updates) where T1 : Org.Neo4j.Kernel.Api.Index.IndexEntryUpdate <T1> { return(throwing(() => { // Entity ids that have been removed, so that additions can reuse them IList <long> removed = new List <long>(); RandomValues randomValues = RandomValues.create(new Random(Random.seed() + THREADS)); while (insertersDone.CurrentCount > 0) { // Do updates now and then Thread.Sleep(10); updateLock.writeLock().@lock(); try { using (IndexUpdater updater = _populator.newPopulatingUpdater(_nodePropertyAccessor)) { for (int i = 0; i < THREADS; i++) { IList <IndexEntryUpdate <object> > batch = lastBatches.get(i); if (batch != null) { IndexEntryUpdate <object> update = null; switch (randomValues.Next(3)) { case 0: // add if (!removed.Empty) { long?id = removed.remove(randomValues.Next(removed.size())); update = add(id, Descriptor, ValueGenerator.apply(randomValues)); } break; case 1: // remove IndexEntryUpdate <object> removal = batch.get(randomValues.Next(batch.size())); update = remove(removal.EntityId, Descriptor, removal.values()); removed.add(removal.EntityId); break; case 2: // change removal = batch.get(randomValues.Next(batch.size())); change(removal.EntityId, Descriptor, removal.values(), toArray(ValueGenerator.apply(randomValues))); break; default: throw new System.ArgumentException(); } if (update != null) { updater.process(update); updates.Add(update); } } } } } finally { updateLock.writeLock().unlock(); } } })); }