blob: d5946e3d7330ab474a69db0957163635647b9e94 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using Lucene.Net.Support;
using NUnit.Framework;
using WhitespaceAnalyzer = Lucene.Net.Analysis.WhitespaceAnalyzer;
using Document = Lucene.Net.Documents.Document;
using Field = Lucene.Net.Documents.Field;
using MaxFieldLength = Lucene.Net.Index.IndexWriter.MaxFieldLength;
using Directory = Lucene.Net.Store.Directory;
using MockRAMDirectory = Lucene.Net.Store.MockRAMDirectory;
using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
namespace Lucene.Net.Index
{
/// <summary> Test class to illustrate using IndexDeletionPolicy to provide multi-level rollback capability.
/// This test case creates an index of records 1 to 100, introducing a commit point every 10 records.
///
/// A "keep all" deletion policy is used to ensure we keep all commit points for testing purposes
/// </summary>
[TestFixture]
public class TestTransactionRollback:LuceneTestCase
{
private const System.String FIELD_RECORD_ID = "record_id";
private Directory dir;
//Rolls back index to a chosen ID
private void RollBackLast(int id)
{
// System.out.println("Attempting to rollback to "+id);
System.String ids = "-" + id;
IndexCommit last = null;
var commits = IndexReader.ListCommits(dir);
for (System.Collections.IEnumerator iterator = commits.GetEnumerator(); iterator.MoveNext(); )
{
IndexCommit commit = (IndexCommit) iterator.Current;
System.Collections.Generic.IDictionary<string, string> ud = commit.UserData;
if (ud.Count > 0)
if (((System.String) ud["index"]).EndsWith(ids))
last = commit;
}
if (last == null)
throw new System.SystemException("Couldn't find commit point " + id);
IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer(), new RollbackDeletionPolicy(this, id), MaxFieldLength.UNLIMITED, last);
System.Collections.Generic.IDictionary<string, string> data = new System.Collections.Generic.Dictionary<string, string>();
data["index"] = "Rolled back to 1-" + id;
w.Commit(data);
w.Close();
}
[Test]
public virtual void TestRepeatedRollBacks()
{
int expectedLastRecordId = 100;
while (expectedLastRecordId > 10)
{
expectedLastRecordId -= 10;
RollBackLast(expectedLastRecordId);
System.Collections.BitArray expecteds = new System.Collections.BitArray((100 % 64 == 0?100 / 64:100 / 64 + 1) * 64);
for (int i = 1; i < (expectedLastRecordId + 1); i++) { expecteds.Set(i, true); }
CheckExpecteds(expecteds);
}
}
private void CheckExpecteds(System.Collections.BitArray expecteds)
{
IndexReader r = IndexReader.Open(dir, true);
//Perhaps not the most efficient approach but meets our needs here.
for (int i = 0; i < r.MaxDoc; i++)
{
if (!r.IsDeleted(i))
{
System.String sval = r.Document(i).Get(FIELD_RECORD_ID);
if (sval != null)
{
int val = System.Int32.Parse(sval);
Assert.IsTrue(expecteds.Get(val), "Did not expect document #" + val);
expecteds.Set(val, false);
}
}
}
r.Close();
Assert.AreEqual(0, BitSetSupport.Cardinality(expecteds), "Should have 0 docs remaining ");
}
/*
private void showAvailableCommitPoints() throws Exception {
Collection commits = IndexReader.listCommits(dir);
for (Iterator iterator = commits.iterator(); iterator.hasNext();) {
IndexCommit comm = (IndexCommit) iterator.next();
System.out.print("\t Available commit point:["+comm.getUserData()+"] files=");
Collection files = comm.getFileNames();
for (Iterator iterator2 = files.iterator(); iterator2.hasNext();) {
String filename = (String) iterator2.next();
System.out.print(filename+", ");
}
System.out.println();
}
}
*/
[SetUp]
public override void SetUp()
{
base.SetUp();
dir = new MockRAMDirectory();
//Build index, of records 1 to 100, committing after each batch of 10
IndexDeletionPolicy sdp = new KeepAllDeletionPolicy(this);
IndexWriter w = new IndexWriter(dir, new WhitespaceAnalyzer(), sdp, MaxFieldLength.UNLIMITED);
for (int currentRecordId = 1; currentRecordId <= 100; currentRecordId++)
{
Document doc = new Document();
doc.Add(new Field(FIELD_RECORD_ID, "" + currentRecordId, Field.Store.YES, Field.Index.ANALYZED));
w.AddDocument(doc);
if (currentRecordId % 10 == 0)
{
System.Collections.Generic.IDictionary<string, string> data = new System.Collections.Generic.Dictionary<string,string>();
data["index"] = "records 1-" + currentRecordId;
w.Commit(data);
}
}
w.Close();
}
// Rolls back to previous commit point
internal class RollbackDeletionPolicy : IndexDeletionPolicy
{
private void InitBlock(TestTransactionRollback enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private TestTransactionRollback enclosingInstance;
public TestTransactionRollback Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
private int rollbackPoint;
public RollbackDeletionPolicy(TestTransactionRollback enclosingInstance, int rollbackPoint)
{
InitBlock(enclosingInstance);
this.rollbackPoint = rollbackPoint;
}
public virtual void OnCommit<T>(IList<T> commits) where T : IndexCommit
{
}
public virtual void OnInit<T>(IList<T> commits) where T : IndexCommit
{
for (System.Collections.IEnumerator iterator = commits.GetEnumerator(); iterator.MoveNext(); )
{
IndexCommit commit = (IndexCommit) iterator.Current;
System.Collections.Generic.IDictionary<string, string> userData = commit.UserData;
if (userData.Count > 0)
{
// Label for a commit point is "Records 1-30"
// This code reads the last id ("30" in this example) and deletes it
// if it is after the desired rollback point
System.String x = (System.String) userData["index"];
System.String lastVal = x.Substring(x.LastIndexOf("-") + 1);
int last = System.Int32.Parse(lastVal);
if (last > rollbackPoint)
{
/*
System.out.print("\tRolling back commit point:" +
" UserData="+commit.getUserData() +") ("+(commits.size()-1)+" commit points left) files=");
Collection files = commit.getFileNames();
for (Iterator iterator2 = files.iterator(); iterator2.hasNext();) {
System.out.print(" "+iterator2.next());
}
System.out.println();
*/
commit.Delete();
}
}
}
}
}
internal class DeleteLastCommitPolicy : IndexDeletionPolicy
{
public DeleteLastCommitPolicy(TestTransactionRollback enclosingInstance)
{
InitBlock(enclosingInstance);
}
private void InitBlock(TestTransactionRollback enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private TestTransactionRollback enclosingInstance;
public TestTransactionRollback Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
public virtual void OnCommit<T>(IList<T> commits) where T : IndexCommit
{
}
public virtual void OnInit<T>(IList<T> commits) where T : IndexCommit
{
commits[commits.Count - 1].Delete();
}
}
[Test]
public virtual void TestRollbackDeletionPolicy()
{
for (int i = 0; i < 2; i++)
{
// Unless you specify a prior commit point, rollback
// should not work:
new IndexWriter(dir, new WhitespaceAnalyzer(), new DeleteLastCommitPolicy(this), MaxFieldLength.UNLIMITED).Close();
IndexReader r = IndexReader.Open(dir, true);
Assert.AreEqual(100, r.NumDocs());
r.Close();
}
}
// Keeps all commit points (used to build index)
internal class KeepAllDeletionPolicy : IndexDeletionPolicy
{
public KeepAllDeletionPolicy(TestTransactionRollback enclosingInstance)
{
InitBlock(enclosingInstance);
}
private void InitBlock(TestTransactionRollback enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private TestTransactionRollback enclosingInstance;
public TestTransactionRollback Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
public virtual void OnCommit<T>(IList<T> commits) where T : IndexCommit
{
}
public virtual void OnInit<T>(IList<T> commits) where T : IndexCommit
{
}
}
}
}