public void TableCache_IndexDoesNotResurrectAfterExpiring() { var conditions = new SearchConditions(); conditions.AddCondition("Author", new SearchCondition(ScanOperator.NotEqual, Guid.NewGuid().ToString().ToDynamoDbEntry(typeof(string)))); // there should be no index yet Assert.IsNull(this.TableCache.GetEntities(conditions, null, null, false)); // creating an index using (var indexCreator = this.TableCache.StartCreatingIndex(conditions)) { indexCreator.AddEntityToIndex(new EntityKey(Guid.NewGuid(), Guid.NewGuid()), this.ToDocumentConverter(BooksHelper.CreateBook(persistToDynamoDb: false))); indexCreator.AddEntityToIndex(new EntityKey(Guid.NewGuid(), Guid.NewGuid()), this.ToDocumentConverter(BooksHelper.CreateBook(persistToDynamoDb: false))); } this.DropIndexEntityFromCache(conditions.Key); // now updating the same index this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document> { { new EntityKey(Guid.NewGuid(), Guid.NewGuid()), this.ToDocumentConverter(BooksHelper.CreateBook(persistToDynamoDb: false)) } }, new Dictionary <EntityKey, Document>(), new EntityKey[] { } ); // the index should still be dropped Assert.IsNull(this.TableCache.GetEntities(conditions, null, null, false)); Assert.IsNull(this.TableCache.GetEntities(conditions, null, null, false)); }
public void TableCache_LocalChangesAreNeverOverwrittenWhenCreatingAnIndex() { var bookKey1 = new EntityKey(1, 1); var book1 = BooksHelper.CreateBook(author: "Mark Twain", numPages: 1, persistToDynamoDb: false); var bookKey2 = new EntityKey(2, 2); var book2 = BooksHelper.CreateBook(author: "Mark Twain", numPages: 2, persistToDynamoDb: false); var book21 = BooksHelper.CreateBook(author: "Mark Twain", numPages: 21, persistToDynamoDb: false); var bookKey3 = new EntityKey(3, 3); var book3 = BooksHelper.CreateBook(author: "Mark Twain", numPages: 3, persistToDynamoDb: false); // creating and filling one index with a filter var index1 = new SearchConditions(); index1.AddCondition("Author", new SearchCondition(ScanOperator.Equal, "Mark Twain".ToDynamoDbEntry(typeof(string)))); using (var indexCreator = this.TableCache.StartCreatingIndex(index1)) { indexCreator.AddEntityToIndex(bookKey1, this.ToDocumentConverter(book1)); indexCreator.AddEntityToIndex(bookKey2, this.ToDocumentConverter(book2)); } // now start creating another index var index2 = new SearchConditions(); using (var indexCreator = this.TableCache.StartCreatingIndex(index2)) { // loading some garnish indexCreator.AddEntityToIndex(new EntityKey(Guid.NewGuid(), Guid.NewGuid()), this.ToDocumentConverter(BooksHelper.CreateBook(author: "Mark Twain", persistToDynamoDb: false))); indexCreator.AddEntityToIndex(new EntityKey(Guid.NewGuid(), Guid.NewGuid()), this.ToDocumentConverter(BooksHelper.CreateBook(author: "Mark Twain", persistToDynamoDb: false))); // in parallel modifying existing index this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document> { { bookKey3, this.ToDocumentConverter(book3) } }, new Dictionary <EntityKey, Document> { { bookKey2, this.ToDocumentConverter(book21) } }, new [] { bookKey1 } ); indexCreator.AddEntityToIndex(new EntityKey(Guid.NewGuid(), Guid.NewGuid()), this.ToDocumentConverter(BooksHelper.CreateBook(author: "Mark Twain", persistToDynamoDb: false))); // loading the same books to the second index - these should be discarded indexCreator.AddEntityToIndex(bookKey2, this.ToDocumentConverter(book2)); indexCreator.AddEntityToIndex(bookKey1, this.ToDocumentConverter(book1)); } // the second index shouldn't be created Assert.IsNull(this.TableCache.GetEntities(index2, null, null, false)); // the first index should now contain book3 and book21 var expectedBooks = new[] { book3, book21 }; var loadedBooks = this.TableCache.GetEntities(index1, null, "NumPages", false).Select(d => (Book)d.ToObject(typeof(Book))); this.DeepCompareBookCollections(expectedBooks, loadedBooks); }
public void TableCache_EntityModificationIsReflectedInIndexes() { var book = BooksHelper.CreateBook(numPages: 150, persistToDynamoDb: false); var bookKey = new EntityKey(Guid.NewGuid(), Guid.NewGuid()); // creating two filters var filter1 = new SearchConditions(); filter1.AddCondition("NumPages", new SearchCondition(ScanOperator.GreaterThan, 100.ToDynamoDbEntry(typeof(int)))); var filter2 = new SearchConditions(); filter2.AddCondition("NumPages", new SearchCondition(ScanOperator.LessThanOrEqual, 100.ToDynamoDbEntry(typeof(int)))); // creating two indexes using (var indexCreator = this.TableCache.StartCreatingIndex(filter1)) { indexCreator.AddEntityToIndex(bookKey, this.ToDocumentConverter(book)); } using (this.TableCache.StartCreatingIndex(filter2)) { } // now modifying the book so, that it should disappear in index1 and appear in index2 book.NumPages = 50; this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document>(), new Dictionary <EntityKey, Document> { { bookKey, this.ToDocumentConverter(book) } }, new EntityKey[0] ); // checking index sizes Assert.AreEqual(0, this.TableCache.GetEntities(filter1, null, null, false).Count()); Assert.AreEqual(1, this.TableCache.GetEntities(filter2, null, null, false).Count()); }
public void TableCache_IndexIsDiscardedIfBeingCreatedTwiceInParallel() { // creating an empty index var conditions = new SearchConditions(); conditions.AddCondition("PublishYear", new SearchCondition(ScanOperator.IsNull)); this._cacheHitCount = 0; this._cacheMissCount = 0; Assert.IsNull(this.TableCache.GetEntities(conditions, null, null, false)); Assert.AreEqual(this._cacheHitCount, 0); Assert.AreNotEqual(this._cacheMissCount, 0); // creating an index and interrupting it's creation using (this.TableCache.StartCreatingIndex(conditions)) { this.TableCache.StartCreatingIndex(conditions); } this._cacheHitCount = 0; this._cacheMissCount = 0; Assert.IsNull(this.TableCache.GetEntities(conditions, null, null, false)); Assert.AreEqual(this._cacheHitCount, 0); Assert.AreNotEqual(this._cacheMissCount, 0); // one more time this._cacheHitCount = 0; this._cacheMissCount = 0; Assert.IsNull(this.TableCache.GetEntities(conditions, null, null, false)); Assert.AreEqual(this._cacheHitCount, 0); Assert.AreNotEqual(this._cacheMissCount, 0); }
public void TableCache_ManyLargeIndexesAreCreatedAndUpdated() { const int IndexCount = 10; const int IndexSize = 100; const int FilterSize = 10; var filters = new Dictionary <SearchConditions, List <EntityKey> >(); var dt = DateTime.Parse("1601-01-01"); for (int i = 0; i < IndexCount; i++) { var filter = new SearchConditions(); filter.AddCondition("Name", new SearchCondition(ScanOperator.Equal, i.ToString().ToDynamoDbEntry(typeof(string)))); for (int j = 0; j < FilterSize; j++) { dt = dt + TimeSpan.FromSeconds(i); filter.AddCondition("LastRentTime", new SearchCondition(ScanOperator.GreaterThan, dt.ToDynamoDbEntry(typeof(DateTime)))); } var entityKeys = new List <EntityKey>(); for (int j = 0; j < IndexSize; j++) { entityKeys.Add(new EntityKey(Guid.NewGuid(), Guid.NewGuid())); } filters[filter] = entityKeys; } Parallel.ForEach(filters, kv => { var doc = this.ToDocumentConverter(BooksHelper.CreateBook(persistToDynamoDb: false)); var filter = kv.Key; using (var indexCreator = this.TableCache.StartCreatingIndex(filter)) { foreach (var k in kv.Value) { indexCreator.AddEntityToIndex(k, doc); } } }); // now sequentially removing all the entities except one in each index foreach (var kv in filters) { foreach (var k in kv.Value.Skip(1)) { this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document>(), new Dictionary <EntityKey, Document>(), new[] { k } ); } } // now checking, that each index contains only one entity Parallel.ForEach(filters, kv => { var loadedBooks = this.TableCache.GetEntities(kv.Key, null, null, true); Assert.AreEqual(1, loadedBooks.Count()); }); }
public void TableCache_IndexIsModifiedSuccessfully() { // creating two filters var allEntitiesFilter = new SearchConditions(); var greaterThanFilter = new SearchConditions(); greaterThanFilter.AddCondition("Author", new SearchCondition(ScanOperator.Equal, "Mark Twain".ToDynamoDbEntry(typeof(string)))); greaterThanFilter.AddCondition("LastRentTime", new SearchCondition(ScanOperator.GreaterThan, DateTime.Parse("2010-01-31").ToDynamoDbEntry(typeof(DateTime)))); // creating two empty indexes using (this.TableCache.StartCreatingIndex(greaterThanFilter)) { } using (this.TableCache.StartCreatingIndex(allEntitiesFilter)) { } // checking that indexes are empty Assert.AreEqual(0, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); Assert.AreEqual(0, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); // adding a book outside the search filter var book1 = BooksHelper.CreateBook(author: "Mark Twain", lastRentTime: DateTime.MinValue, persistToDynamoDb: false); var bookKey1 = new EntityKey(Guid.NewGuid(), Guid.NewGuid()); this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document> { { bookKey1, this.ToDocumentConverter(book1) } }, new Dictionary <EntityKey, Document>(), new EntityKey[0] ); // checking index sizes Assert.AreEqual(0, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); Assert.AreEqual(1, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); // adding a book inside the search filter var book2 = BooksHelper.CreateBook(author: "Mark Twain", lastRentTime: DateTime.Now, persistToDynamoDb: false); var bookKey2 = new EntityKey(Guid.NewGuid(), Guid.NewGuid()); this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document> { { bookKey2, this.ToDocumentConverter(book2) } }, new Dictionary <EntityKey, Document>(), new EntityKey[0] ); // checking index sizes Assert.AreEqual(1, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); Assert.AreEqual(2, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); // adding one more book inside the search filter var book3 = BooksHelper.CreateBook(author: "Mark Twain", lastRentTime: DateTime.Now, persistToDynamoDb: false); var bookKey3 = new EntityKey(Guid.NewGuid(), Guid.NewGuid()); this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document> { { bookKey3, this.ToDocumentConverter(book3) } }, new Dictionary <EntityKey, Document>(), new EntityKey[0] ); // checking index sizes Assert.AreEqual(2, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); Assert.AreEqual(3, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); // modifying an entity book3.LastRentTime = DateTime.Parse("2009-01-01"); this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document>(), new Dictionary <EntityKey, Document> { { bookKey3, this.ToDocumentConverter(book3) } }, new EntityKey[0] ); // checking index sizes Assert.AreEqual(1, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); Assert.AreEqual(3, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); // removing one entity this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document>(), new Dictionary <EntityKey, Document>(), new [] { bookKey1 } ); // checking index sizes Assert.AreEqual(1, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); Assert.AreEqual(2, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); // removing other two entities this.TableCache.UpdateCacheAndIndexes ( new Dictionary <EntityKey, Document>(), new Dictionary <EntityKey, Document>(), new [] { bookKey2, bookKey3 } ); // checking index sizes Assert.AreEqual(0, this.TableCache.GetEntities(greaterThanFilter, null, null, false).Count()); Assert.AreEqual(0, this.TableCache.GetEntities(allEntitiesFilter, null, null, false).Count()); }