@Test public void testBasicOperation() throws ConnectionException, InterruptedException { ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization")); IntegerField field = new IntegerField("count", 5); Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity"); UUID version = UUIDGenerator.newTimeUUID(); UniqueValue stored = new UniqueValueImpl(field, entityId, version); strategy.write(scope, stored).execute(); UniqueValueSet fields = strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field)); UniqueValue retrieved = fields.getValue(field.getName()); Assert.assertNotNull(retrieved); assertEquals(stored, retrieved); Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId); assertTrue(allFieldsWritten.hasNext()); // test this interface. In most cases, we won't know the field name, so we want them all UniqueValue allFieldsValue = allFieldsWritten.next(); Assert.assertNotNull(allFieldsValue); assertEquals(field, allFieldsValue.getField()); assertEquals(version, allFieldsValue.getEntityVersion()); assertFalse(allFieldsWritten.hasNext()); }
@Test public void testCapitalizationFixes() throws ConnectionException { ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization")); StringField field = new StringField("count", "MiXeD CaSe"); Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity"); UUID version = UUIDGenerator.newTimeUUID(); UniqueValue stored = new UniqueValueImpl(field, entityId, version); strategy.write(scope, stored).execute(); UniqueValueSet fields = strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field)); UniqueValue value = fields.getValue(field.getName()); assertEquals(field.getName(), value.getField().getName()); assertEquals(entityId, value.getEntityId()); // now test will all upper and all lower, we should get it all the same fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton(new StringField(field.getName(), "MIXED CASE"))); value = fields.getValue(field.getName()); assertEquals(field.getName(), value.getField().getName()); assertEquals(entityId, value.getEntityId()); fields = strategy.load( scope, entityId.getType(), Collections.<Field>singleton(new StringField(field.getName(), "mixed case"))); value = fields.getValue(field.getName()); assertEquals(field.getName(), value.getField().getName()); assertEquals(entityId, value.getEntityId()); Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId); assertTrue(allFieldsWritten.hasNext()); // test this interface. In most cases, we won't know the field name, so we want them all UniqueValue writtenFieldEntry = allFieldsWritten.next(); Assert.assertNotNull(writtenFieldEntry); assertEquals(field.getName(), writtenFieldEntry.getField().getName()); assertEquals(field.getValue().toLowerCase(), writtenFieldEntry.getField().getValue()); assertEquals(version, writtenFieldEntry.getEntityVersion()); assertFalse(allFieldsWritten.hasNext()); }
/** * Queue up an indexOperationMessage for multi region execution * * @param indexOperationMessage */ public void queueIndexOperationMessage(final IndexOperationMessage indexOperationMessage) { // don't try to produce something with nothing if (indexOperationMessage == null || indexOperationMessage.isEmpty()) { return; } final String jsonValue = ObjectJsonSerializer.INSTANCE.toString(indexOperationMessage); final UUID newMessageId = UUIDGenerator.newTimeUUID(); final int expirationTimeInSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(indexProcessorFig.getIndexMessageTtl()); // write to the map in ES esMapPersistence.putString(newMessageId.toString(), jsonValue, expirationTimeInSeconds); // now queue up the index message final ElasticsearchIndexEvent elasticsearchIndexEvent = new ElasticsearchIndexEvent(queueFig.getPrimaryRegion(), newMessageId); // send to the topic so all regions index the batch offerTopic(elasticsearchIndexEvent); }
@Test public void testWriteWithTTL() throws InterruptedException, ConnectionException { ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization")); // write object that lives 2 seconds IntegerField field = new IntegerField("count", 5); Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity"); UUID version = UUIDGenerator.newTimeUUID(); UniqueValue stored = new UniqueValueImpl(field, entityId, version); strategy.write(scope, stored, 5).execute(); Thread.sleep(1000); // waited one sec, should be still here UniqueValueSet fields = strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field)); UniqueValue retrieved = fields.getValue(field.getName()); Assert.assertNotNull(retrieved); assertEquals(stored, retrieved); Thread.sleep(5000); // wait another second, should be gone now fields = strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field)); UniqueValue nullExpected = fields.getValue(field.getName()); Assert.assertNull(nullExpected); // we still want to retain the log entry, even if we don't retain the unique value. Deleting // something // that doesn't exist is a tombstone, but so is the timeout. Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId); assertTrue(allFieldsWritten.hasNext()); // test this interface. In most cases, we won't know the field name, so we want them all UniqueValue writtenFieldEntry = allFieldsWritten.next(); Assert.assertNotNull(writtenFieldEntry); assertEquals(field, writtenFieldEntry.getField()); assertEquals(version, writtenFieldEntry.getEntityVersion()); assertFalse(allFieldsWritten.hasNext()); }
@Test(expected = NullPointerException.class) public void loadListParamEntityId() throws ConnectionException { logEntryStrategy.load( new ApplicationScopeImpl(new SimpleId("organization")), null, UUIDGenerator.newTimeUUID(), 1); }
@Test(expected = IllegalArgumentException.class) public void loadListParamSize() throws ConnectionException { logEntryStrategy.load( new ApplicationScopeImpl(new SimpleId("organization")), new SimpleId("test"), UUIDGenerator.newTimeUUID(), 0); }
@Test public void getMultipleEntries() throws ConnectionException { final Id applicationId = new SimpleId("application"); ApplicationScope context = new ApplicationScopeImpl(applicationId); final Id id = new SimpleId("test"); int count = 10; final UUID[] versions = new UUID[count]; final Stage COMPLETE = Stage.COMPLETE; final MvccLogEntry[] entries = new MvccLogEntry[count]; for (int i = 0; i < count; i++) { versions[i] = UUIDGenerator.newTimeUUID(); entries[i] = new MvccLogEntryImpl(id, versions[i], COMPLETE, MvccLogEntry.State.COMPLETE); logEntryStrategy.write(context, entries[i]).execute(); // Read it back MvccLogEntry returned = logEntryStrategy.load(context, Collections.singleton(id), versions[i]).getMaxVersion(id); assertNotNull("Returned value should not be null", returned); assertEquals("Returned should equal the saved", entries[i], returned); } // now do a range scan from the end List<MvccLogEntry> results = logEntryStrategy.load(context, id, versions[count - 1], count); assertEquals(count, results.size()); for (int i = 0; i < count; i++) { final MvccLogEntry saved = entries[count - i - 1]; final MvccLogEntry returned = results.get(i); assertEquals("Entry was not equal to the saved value", saved, returned); } // now delete them all and ensure we get no results back for (int i = 0; i < count; i++) { logEntryStrategy.delete(context, id, versions[i]).execute(); } results = logEntryStrategy.load(context, id, versions[versions.length - 1], versions.length); assertEquals("All log entries were deleted", 0, results.size()); }
@Override public ReIndexStatus rebuildIndex(final ReIndexRequestBuilder reIndexRequestBuilder) { // load our last emitted Scope if a cursor is present final Optional<EdgeScope> cursor = parseCursor(reIndexRequestBuilder.getCursor()); final CursorSeek<Edge> cursorSeek = getResumeEdge(cursor); final Optional<ApplicationScope> appId = reIndexRequestBuilder.getApplicationScope(); Preconditions.checkArgument( !(cursor.isPresent() && appId.isPresent()), "You cannot specify an app id and a cursor. When resuming with cursor you must omit the appid"); final Observable<ApplicationScope> applicationScopes = getApplications(cursor, appId); final String jobId = StringUtils.sanitizeUUID(UUIDGenerator.newTimeUUID()); final long modifiedSince = reIndexRequestBuilder.getUpdateTimestamp().or(Long.MIN_VALUE); // create an observable that loads a batch to be indexed final Observable<List<EdgeScope>> runningReIndex = allEntityIdsObservable .getEdgesToEntities( applicationScopes, reIndexRequestBuilder.getCollectionName(), cursorSeek.getSeekValue()) .buffer(indexProcessorFig.getReindexBufferSize()) .doOnNext( edges -> { logger.info("Sending batch of {} to be indexed.", edges.size()); indexService.indexBatch(edges, modifiedSince); }); // start our sampler and state persistence // take a sample every sample interval to allow us to resume state with minimal loss // create our flushing collector and flush the edge scopes to it runningReIndex .collect( () -> new FlushingCollector(jobId), ((flushingCollector, edgeScopes) -> flushingCollector.flushBuffer(edgeScopes))) .doOnNext(flushingCollector -> flushingCollector.complete()) // subscribe on our I/O scheduler and run the task .subscribeOn(Schedulers.io()) .subscribe(); // want reindex to continually run so leave subscribe. return new ReIndexStatus(jobId, Status.STARTED, 0, 0); }
@Test public void testDelete() throws ConnectionException { ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization")); IntegerField field = new IntegerField("count", 5); Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity"); UUID version = UUIDGenerator.newTimeUUID(); UniqueValue stored = new UniqueValueImpl(field, entityId, version); strategy.write(scope, stored).execute(); strategy.delete(scope, stored).execute(); UniqueValueSet fields = strategy.load(scope, entityId.getType(), Collections.<Field>singleton(field)); UniqueValue nullExpected = fields.getValue(field.getName()); Assert.assertNull(nullExpected); Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId); assertFalse("No entries left", allFieldsWritten.hasNext()); }
@Test public void loadNoData() throws ConnectionException { final Id applicationId = new SimpleId("application"); ApplicationScope context = new ApplicationScopeImpl(applicationId); final Id id = new SimpleId("test"); final UUID version = UUIDGenerator.newTimeUUID(); MvccLogEntry returned = logEntryStrategy.load(context, Collections.singleton(id), version).getMaxVersion(id); assertNull("Returned value should not exist", returned); }
@Test public void createAndDeleteEntries() throws ConnectionException { final Id applicationId = new SimpleId("application"); ApplicationScope context = new ApplicationScopeImpl(applicationId); final Id id = new SimpleId("test"); final int size = 10; final List<MvccLogEntry> savedEntries = new ArrayList<>(size); for (int i = 0; i < size; i++) { final UUID version = UUIDGenerator.newTimeUUID(); MvccLogEntry saved = new MvccLogEntryImpl(id, version, Stage.COMMITTED, MvccLogEntry.State.COMPLETE); logEntryStrategy.write(context, saved).execute(); savedEntries.add(saved); } // now test we get them all back final List<MvccLogEntry> results = logEntryStrategy.loadReversed(context, id, null, size); assertEquals(size, results.size()); // assert they're the same for (int i = 0; i < size; i++) { assertEquals(savedEntries.get(i), results.get(i)); } // now delete them all for (final MvccLogEntry mvccLogEntry : savedEntries) { logEntryStrategy.delete(context, id, mvccLogEntry.getVersion()).execute(); } // now get them back, should be empty final List<MvccLogEntry> emptyResults = logEntryStrategy.loadReversed(context, id, null, size); assertEquals(0, emptyResults.size()); }
@Test public void createAndDelete() throws ConnectionException { final Id applicationId = new SimpleId("application"); ApplicationScope context = new ApplicationScopeImpl(applicationId); final Id id = new SimpleId("test"); final UUID version = UUIDGenerator.newTimeUUID(); for (Stage stage : Stage.values()) { MvccLogEntry saved = new MvccLogEntryImpl(id, version, stage, MvccLogEntry.State.COMPLETE); logEntryStrategy.write(context, saved).execute(); // Read it back MvccLogEntry returned = logEntryStrategy.load(context, Collections.singleton(id), version).getMaxVersion(id); assertNotNull("Returned value should not be null", returned); assertEquals("Returned should equal the saved", saved, returned); } }
@Test public void twoFieldsPerVersion() throws ConnectionException, InterruptedException { ApplicationScope scope = new ApplicationScopeImpl(new SimpleId("organization")); Id entityId = new SimpleId(UUIDGenerator.newTimeUUID(), "entity"); final UUID version1 = UUIDGenerator.newTimeUUID(); // write V1 of everything IntegerField version1Field1 = new IntegerField("count", 1); StringField version1Field2 = new StringField("field", "v1value"); UniqueValue version1Field1Value = new UniqueValueImpl(version1Field1, entityId, version1); UniqueValue version1Field2Value = new UniqueValueImpl(version1Field2, entityId, version1); final MutationBatch batch = strategy.write(scope, version1Field1Value); batch.mergeShallow(strategy.write(scope, version1Field2Value)); // write V2 of everything final UUID version2 = UUIDGenerator.newTimeUUID(); IntegerField version2Field1 = new IntegerField("count", 2); StringField version2Field2 = new StringField("field", "v2value"); UniqueValue version2Field1Value = new UniqueValueImpl(version2Field1, entityId, version2); UniqueValue version2Field2Value = new UniqueValueImpl(version2Field2, entityId, version2); batch.mergeShallow(strategy.write(scope, version2Field1Value)); batch.mergeShallow(strategy.write(scope, version2Field2Value)); batch.execute(); UniqueValueSet fields = strategy.load( scope, entityId.getType(), Arrays.<Field>asList(version1Field1, version1Field2)); UniqueValue retrieved = fields.getValue(version1Field1.getName()); assertEquals(version1Field1Value, retrieved); retrieved = fields.getValue(version1Field2.getName()); assertEquals(version1Field2Value, retrieved); Iterator<UniqueValue> allFieldsWritten = strategy.getAllUniqueFields(scope, entityId); assertTrue(allFieldsWritten.hasNext()); // test this interface. In most cases, we won't know the field name, so we want them all UniqueValue allFieldsValue = allFieldsWritten.next(); // version 2 fields should come first, ordered by field name assertEquals(version2Field1, allFieldsValue.getField()); assertEquals(version2, allFieldsValue.getEntityVersion()); allFieldsValue = allFieldsWritten.next(); assertEquals(version2Field2, allFieldsValue.getField()); assertEquals(version2, allFieldsValue.getEntityVersion()); // version 1 should come next ordered by field name allFieldsValue = allFieldsWritten.next(); assertEquals(version1Field1, allFieldsValue.getField()); assertEquals(version1, allFieldsValue.getEntityVersion()); allFieldsValue = allFieldsWritten.next(); assertEquals(version1Field2, allFieldsValue.getField()); assertEquals(version1, allFieldsValue.getEntityVersion()); assertFalse(allFieldsWritten.hasNext()); }
@Test(expected = NullPointerException.class) public void loadListParamContext() throws ConnectionException { logEntryStrategy.load(null, new SimpleId("test"), UUIDGenerator.newTimeUUID(), 1); }
@Test(expected = NullPointerException.class) public void loadParamContext() throws ConnectionException { logEntryStrategy.load(null, Collections.<Id>emptyList(), UUIDGenerator.newTimeUUID()); }
@Test public void getReversedEntries() throws ConnectionException { final Id applicationId = new SimpleId("application"); ApplicationScope context = new ApplicationScopeImpl(applicationId); final Id id = new SimpleId("test"); int count = 10; final UUID[] versions = new UUID[count]; final Stage COMPLETE = Stage.COMPLETE; final MvccLogEntry[] entries = new MvccLogEntry[count]; for (int i = 0; i < count; i++) { versions[i] = UUIDGenerator.newTimeUUID(); entries[i] = new MvccLogEntryImpl(id, versions[i], COMPLETE, MvccLogEntry.State.COMPLETE); logEntryStrategy.write(context, entries[i]).execute(); // Read it back MvccLogEntry returned = logEntryStrategy.load(context, Collections.singleton(id), versions[i]).getMaxVersion(id); assertNotNull("Returned value should not be null", returned); assertEquals("Returned should equal the saved", entries[i], returned); } final UUID[] assertVersions = Arrays.copyOf(versions, versions.length); Arrays.sort(assertVersions, (v1, v2) -> UUIDComparator.staticCompare(v1, v2) * -1); // now do a range scan from the end final int half = count / 2; final List<MvccLogEntry> results = logEntryStrategy.loadReversed(context, id, versions[0], half); assertEquals(half, results.size()); for (int i = 0; i < count / 2; i++) { final MvccLogEntry saved = entries[i]; final MvccLogEntry returned = results.get(i); assertEquals("Entry was not equal to the saved value", saved, returned); } // now get the next batch final List<MvccLogEntry> results2 = logEntryStrategy.loadReversed(context, id, versions[half], count); assertEquals(half, results2.size()); for (int i = 0; i < half; i++) { final MvccLogEntry saved = entries[half + i]; final MvccLogEntry returned = results2.get(i); assertEquals("Entry was not equal to the saved value", saved, returned); } // now delete them all and ensure we get no results back for (int i = 0; i < count; i++) { logEntryStrategy.delete(context, id, versions[i]).execute(); } final List<MvccLogEntry> results3 = logEntryStrategy.loadReversed(context, id, null, versions.length); assertEquals("All log entries were deleted", 0, results3.size()); }