| /* |
| * 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 |
| { |
| } |
| } |
| } |
| } |