public void should_allow_multiple_transactions_to_append_records() { const ushort objectType = 128; const int threadCount = 5; var threads = new List <Thread>(); var exceptions = new List <Exception>(); var firstPageNumber = _pageStore.GetFirstIndexPage(objectType); for (var i = 1; i <= threadCount; i++) { var transactionNumber = i; var thread = new Thread(() => { try { var writeTransaction = _database.BeginTransaction(null); _pageStore.BeginTransaction(writeTransaction); var buffer = Encoding.UTF8.GetBytes("Transaction " + transactionNumber); var location = _accessor.Append(firstPageNumber, writeTransaction, (uint)buffer.LongLength); _accessor.Write(writeTransaction, location, buffer); Thread.Sleep(50); _database.CommitTransaction(writeTransaction); _pageStore.CommitTransaction(writeTransaction); _pageStore.FinalizeTransaction(writeTransaction); } catch (Exception ex) { lock (exceptions) exceptions.Add(ex); } }) { Name = "Transaction " + i, IsBackground = true }; threads.Add(thread); } foreach (var thread in threads) { thread.Start(); } foreach (var thread in threads) { thread.Join(); } Assert.AreEqual(0, exceptions.Count); var transaction = _database.BeginTransaction(null); _pageStore.BeginTransaction(transaction); var results = new HashSet <string>(); Action <PageLocation> check = (location) => { using (var page = _pageStore.Get(transaction, location.PageNumber, CacheHints.None)) { var actual = Encoding.UTF8.GetString(page.Data, (int)location.Offset, (int)location.Length); Assert.IsTrue(results.Add(actual)); } }; var record = _accessor.LocateFirst(firstPageNumber, transaction, out object indexLocation); Assert.IsNotNull(record); for (var i = 1; i <= threadCount; i++) { check(record); record = _accessor.LocateNext(firstPageNumber, transaction, indexLocation); } for (var i = 1; i <= threadCount; i++) { Assert.IsTrue(results.Contains("Transaction " + i)); } Assert.IsNull(record); }
public void should_read_and_write_records() { const ushort objectType = 128; var strings = new[] { "The short brown lazy dog couldn't jump over anything", "One, two, buckle my shoe", "YARD (Yet Another Relational Database)", "This is a test, one, two, three, testing", "Blah blah blah", "This should be on a second index page", "OK, I think that's enough now" }; var transaction = _database.BeginTransaction(null); _pageStore.BeginTransaction(transaction); var firstPageNumber = _pageStore.GetFirstIndexPage(objectType); _accessor.Clear(firstPageNumber, transaction); foreach (var s in strings) { var buffer = Encoding.UTF8.GetBytes(s); var recordLocation = _accessor.Append(firstPageNumber, transaction, (uint)buffer.LongLength); _accessor.Write(transaction, recordLocation, buffer); } _database.CommitTransaction(transaction); _pageStore.CommitTransaction(transaction); _pageStore.FinalizeTransaction(transaction); transaction = _database.BeginTransaction(null); _pageStore.BeginTransaction(transaction); Action <PageLocation, string> check = (location, expected) => { Assert.IsNotNull(location); var data = location.ReadAll(transaction, CacheHints.None); var actual = Encoding.UTF8.GetString(data); Assert.AreEqual(expected, actual); }; var record = _accessor.LocateFirst(firstPageNumber, transaction, out object indexLocation); Assert.IsNotNull(record); foreach (var s in strings) { check(record, s); record = _accessor.LocateNext(firstPageNumber, transaction, indexLocation); } Assert.IsNull(record); _database.RollbackTransaction(transaction); _pageStore.RollbackTransaction(transaction); }
public void should_allow_relocking_a_page() { var pageNumber = _pageStore.GetFirstIndexPage(128); // Update a page without a lock var updateTransaction = _database.BeginTransaction(null); _pageStore.BeginTransaction(updateTransaction); _pageStore.Update( updateTransaction, new[] { new PageUpdate { PageNumber = pageNumber, Offset = 3, Data = new byte[] { 98, 99, 100 } } }); // Lock and update the page multiple times for (byte i = 10; i < 15; i++) { _pageStore.Lock(updateTransaction, pageNumber); _pageStore.Update( updateTransaction, new[] { new PageUpdate { PageNumber = pageNumber, Offset = i, Data = new byte[] { i } } }); } // Commit all the changes to disk _database.CommitTransaction(updateTransaction); _pageStore.CommitTransaction(updateTransaction); _pageStore.FinalizeTransaction(updateTransaction); // Check that the changes were written properly var readTransaction = _database.BeginTransaction(null); _pageStore.BeginTransaction(readTransaction); using (var page = _pageStore.Get(readTransaction, pageNumber, CacheHints.None)) { Assert.AreEqual(98, page.Data[3]); Assert.AreEqual(99, page.Data[4]); Assert.AreEqual(100, page.Data[5]); Assert.AreEqual(10, page.Data[10]); Assert.AreEqual(11, page.Data[11]); Assert.AreEqual(12, page.Data[12]); Assert.AreEqual(13, page.Data[13]); Assert.AreEqual(14, page.Data[14]); } _database.RollbackTransaction(readTransaction); _pageStore.RollbackTransaction(readTransaction); }