public override void Run()
{
try
{
while (Operations.Get() > 0)
{
int oper = rand.Next(100);
if (oper < CommitPercent)
{
if (NumCommitting.IncrementAndGet() <= MaxConcurrentCommits)
{
IDictionary<int, long> newCommittedModel;
long version;
DirectoryReader oldReader;
lock (OuterInstance)
{
newCommittedModel = new Dictionary<int, long>(OuterInstance.Model); // take a snapshot
version = OuterInstance.SnapshotCount++;
oldReader = OuterInstance.Reader;
oldReader.IncRef(); // increment the reference since we will use this for reopening
}
DirectoryReader newReader;
if (rand.Next(100) < SoftCommitPercent)
{
// assertU(h.Commit("softCommit","true"));
if (Random().NextBoolean())
{
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": call writer.getReader");
}
newReader = Writer.GetReader(true);
}
else
{
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": reopen reader=" + oldReader + " version=" + version);
}
newReader = DirectoryReader.OpenIfChanged(oldReader, Writer.w, true);
}
}
else
{
// assertU(commit());
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": commit+reopen reader=" + oldReader + " version=" + version);
}
Writer.Commit();
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": now reopen after commit");
}
newReader = DirectoryReader.OpenIfChanged(oldReader);
}
// Code below assumes newReader comes w/
// extra ref:
if (newReader == null)
{
oldReader.IncRef();
newReader = oldReader;
}
oldReader.DecRef();
lock (OuterInstance)
{
// install the new reader if it's newest (and check the current version since another reader may have already been installed)
//System.out.println(Thread.currentThread().getName() + ": newVersion=" + newReader.getVersion());
Debug.Assert(newReader.RefCount > 0);
Debug.Assert(OuterInstance.Reader.RefCount > 0);
if (newReader.Version > OuterInstance.Reader.Version)
{
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": install new reader=" + newReader);
}
OuterInstance.Reader.DecRef();
OuterInstance.Reader = newReader;
// Silly: forces fieldInfos to be
// loaded so we don't hit IOE on later
// reader.toString
newReader.ToString();
// install this snapshot only if it's newer than the current one
if (version >= OuterInstance.CommittedModelClock)
{
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": install new model version=" + version);
}
OuterInstance.CommittedModel = newCommittedModel;
OuterInstance.CommittedModelClock = version;
}
else
{
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": skip install new model version=" + version);
}
}
}
else
{
// if the same reader, don't decRef.
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": skip install new reader=" + newReader);
}
newReader.DecRef();
}
}
}
NumCommitting.DecrementAndGet();
}
else
{
int id = rand.Next(Ndocs);
object sync = OuterInstance.SyncArr[id];
// set the lastId before we actually change it sometimes to try and
// uncover more race conditions between writing and reading
bool before = Random().NextBoolean();
if (before)
{
OuterInstance.LastId = id;
}
// We can't concurrently update the same document and retain our invariants of increasing values
// since we can't guarantee what order the updates will be executed.
lock (sync)
{
long val = OuterInstance.Model[id];
long nextVal = Math.Abs(val) + 1;
if (oper < CommitPercent + DeletePercent)
{
// assertU("<delete><id>" + id + "</id></delete>");
// add tombstone first
if (Tombstones)
{
Document d = new Document();
d.Add(OuterInstance.NewStringField("id", "-" + Convert.ToString(id), Documents.Field.Store.YES));
d.Add(OuterInstance.NewField(OuterInstance.Field, Convert.ToString(nextVal), StoredOnlyType));
Writer.UpdateDocument(new Term("id", "-" + Convert.ToString(id)), d);
}
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": term delDocs id:" + id + " nextVal=" + nextVal);
}
Writer.DeleteDocuments(new Term("id", Convert.ToString(id)));
OuterInstance.Model[id] = -nextVal;
}
else if (oper < CommitPercent + DeletePercent + DeleteByQueryPercent)
{
//assertU("<delete><query>id:" + id + "</query></delete>");
// add tombstone first
if (Tombstones)
{
Document d = new Document();
d.Add(OuterInstance.NewStringField("id", "-" + Convert.ToString(id), Documents.Field.Store.YES));
d.Add(OuterInstance.NewField(OuterInstance.Field, Convert.ToString(nextVal), StoredOnlyType));
Writer.UpdateDocument(new Term("id", "-" + Convert.ToString(id)), d);
}
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": query delDocs id:" + id + " nextVal=" + nextVal);
}
Writer.DeleteDocuments(new TermQuery(new Term("id", Convert.ToString(id))));
OuterInstance.Model[id] = -nextVal;
}
else
{
// assertU(adoc("id",Integer.toString(id), field, Long.toString(nextVal)));
Document d = new Document();
d.Add(OuterInstance.NewStringField("id", Convert.ToString(id), Documents.Field.Store.YES));
d.Add(OuterInstance.NewField(OuterInstance.Field, Convert.ToString(nextVal), StoredOnlyType));
if (VERBOSE)
{
Console.WriteLine("TEST: " + Thread.CurrentThread.Name + ": u id:" + id + " val=" + nextVal);
}
Writer.UpdateDocument(new Term("id", Convert.ToString(id)), d);
if (Tombstones)
{
// remove tombstone after new addition (this should be optional?)
Writer.DeleteDocuments(new Term("id", "-" + Convert.ToString(id)));
}
OuterInstance.Model[id] = nextVal;
}
}
if (!before)
{
OuterInstance.LastId = id;
}
}
}
}
catch (Exception e)
{
Console.WriteLine(Thread.CurrentThread.Name + ": FAILED: unexpected exception");
Console.WriteLine(e.StackTrace);
throw new Exception(e.Message, e);
}
}
}