@Override protected void serializeFields(Object bean, JsonGenerator jgen0, SerializerProvider provider) throws IOException { super.serializeFields(bean, jgen0, provider); Applications applications = (Applications) bean; if (applications.getVersion() != null) { jgen0.writeStringField(versionKey, Long.toString(applications.getVersion())); } if (applications.getAppsHashCode() != null) { jgen0.writeStringField(appsHashCodeKey, applications.getAppsHashCode()); } } }
@Override protected void serializeFields(Object bean, JsonGenerator jgen0, SerializerProvider provider) throws IOException { super.serializeFields(bean, jgen0, provider); Applications applications = (Applications) bean; if (applications.getVersion() != null) { jgen0.writeStringField(versionKey, Long.toString(applications.getVersion())); } if (applications.getAppsHashCode() != null) { jgen0.writeStringField(appsHashCodeKey, applications.getAppsHashCode()); } } }
@Override public void serialize(Applications applications, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStartObject(); jgen.writeStringField(versionDeltaKey, applications.getVersion().toString()); jgen.writeStringField(appHashCodeKey, applications.getAppsHashCode()); jgen.writeObjectField(NODE_APP, applications.getRegisteredApplications()); } }
/** * Reconciles the delta information fetched to see if the hashcodes match. * * @param delta - the delta information fetched previously for reconciliation. * @param reconcileHashCode - the hashcode for comparison. * @return - response * @throws Throwable */ private boolean reconcileAndLogDifference(Applications delta, String reconcileHashCode) throws Throwable { logger.warn("The Reconcile hashcodes do not match, client : {}, server : {}. Getting the full registry", reconcileHashCode, delta.getAppsHashCode()); long currentGeneration = fetchRegistryGeneration.get(); Applications apps = this.fetchRemoteRegistry(false); if (apps == null) { logger.error("The application is null for some reason. Not storing this information"); return false; } if (fetchRegistryGeneration.compareAndSet(currentGeneration, currentGeneration + 1)) { applications.set(apps); applicationsDelta.set(apps); logger.warn("The Reconcile hashcodes after complete sync up, client : {}, server : {}.", getApplications().getReconcileHashCode(), delta.getAppsHashCode()); return true; }else { logger.warn("Not setting the applications map as another thread has advanced the update generation"); return true; // still return true } }
public Applications takeDeltaForDelete(boolean useInstanceId, int instanceCount) { List<InstanceInfo> instanceInfoList = new ArrayList<>(); for (int i = 0; i < instanceCount; i ++) { instanceInfoList.add(this.generateInstanceInfo(i, i, useInstanceId, ActionType.DELETED)); } Applications delete = EurekaEntityFunctions.toApplications(toApplicationMap(instanceInfoList)); allApplications = mergeApplications(allApplications, delete); delete.setAppsHashCode(allApplications.getAppsHashCode()); return delete; }
if ((!reconcileHashCode.equals(delta.getAppsHashCode()))) { return reconcileAndLogDifference(delta, reconcileHashCode);
getAndStoreFullRegistry(); } else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) { logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode()); String reconcileHashCode = ""; if (fetchRegistryUpdateLock.tryLock()) { if (!reconcileHashCode.equals(delta.getAppsHashCode()) || clientConfig.shouldLogDeltaDiff()) { logger.debug("Ignoring delta update with apps hashcode {}, as another thread is updating it already", delta.getAppsHashCode());
/** * Generate pay load with both JSON and XML formats for all applications. */ private String getPayLoad(Key key, Applications apps) { EncoderWrapper encoderWrapper = serverCodecs.getEncoder(key.getType(), key.getEurekaAccept()); String result; try { result = encoderWrapper.encode(apps); } catch (Exception e) { logger.error("Failed to encode the payload for all apps", e); return ""; } if(logger.isDebugEnabled()) { logger.debug("New application cache entry {} with apps hashcode {}", key.toStringCompact(), apps.getAppsHashCode()); } return result; }
Applications delta = client.getDelta().getEntity(); Applications merged = EurekaEntityFunctions.mergeApplications(applications, delta); if (merged.getAppsHashCode().equals(delta.getAppsHashCode())) { System.out.println("Hash codes match: " + delta.getAppsHashCode() + "(delta count=" + countInstances(delta) + ')'); applications = merged; } else { System.out.println("ERROR: hash codes do not match (" + delta.getAppsHashCode() + "(delta) != " + merged.getAppsHashCode() + " (merged) != " + applications.getAppsHashCode() + "(old apps)" + "(delta count=" + countInstances(delta) + ')' );
} else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) { localRegionApps.set(this.filterAndShuffle(apps)); logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode()); } else { logger.warn("Not updating applications as another thread is updating it already");
public Applications takeDelta(int count) { if (currentIt == null) { currentIt = serviceIterator(); allApplications = new Applications(); } List<InstanceInfo> instanceBatch = new ArrayList<InstanceInfo>(); for (int i = 0; i < count; i++) { InstanceInfo next = currentIt.next(); next.setActionType(ActionType.ADDED); instanceBatch.add(next); } Applications nextBatch = EurekaEntityFunctions.toApplications(toApplicationMap(instanceBatch)); allApplications = mergeApplications(allApplications, nextBatch); nextBatch.setAppsHashCode(allApplications.getAppsHashCode()); return nextBatch; }
reconcileHashCode, delta.getAppsHashCode()); "The Reconcile hashcodes after complete sync up, client : {}, server : {}.", getApplications().getReconcileHashCode(), delta.getAppsHashCode()); } else { logger.warn("Not setting the applications map as another thread has advanced the update generation");
@Test public void testApplicationsHashAndVersion() { Applications applications = new Applications("appsHashCode", 1L, Collections.emptyList()); assertEquals(1L, (long)applications.getVersion()); assertEquals("appsHashCode", applications.getAppsHashCode()); }
@Override public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { Applications apps = (Applications) source; writer.startNode(VERSIONS_DELTA); writer.setValue(apps.getVersion().toString()); writer.endNode(); writer.startNode(APPS_HASHCODE); writer.setValue(apps.getAppsHashCode()); writer.endNode(); for (Application app : apps.getRegisteredApplications()) { writer.startNode(NODE_APP); context.convertAnother(app); writer.endNode(); } }
@Test public void testAppsHashCodeAfterRefresh() throws InterruptedException { Assert.assertEquals("UP_1_", registry.getApplicationsFromAllRemoteRegions().getAppsHashCode()); registerInstanceLocally(createLocalInstance(LOCAL_REGION_INSTANCE_2_HOSTNAME)); waitForDeltaToBeRetrieved(); Assert.assertEquals("UP_2_", registry.getApplicationsFromAllRemoteRegions().getAppsHashCode()); }
@Test public void testAppsHashCode() throws Exception { setUp(true); Applications applications = client.getApplications(); Assert.assertEquals("UP_1_", applications.getAppsHashCode()); }
@Test public void testVersionAndAppHash() { Applications apps = new Applications(); assertEquals(-1L, (long)apps.getVersion()); assertNull(apps.getAppsHashCode()); apps.setVersion(101L); apps.setAppsHashCode("UP_5_DOWN_6_"); assertEquals(101L, (long)apps.getVersion()); assertEquals("UP_5_DOWN_6_", apps.getAppsHashCode()); }
@Test public void testAppsHashCodeAfterRefresh() throws Exception { InstanceInfoGenerator instanceGen = InstanceInfoGenerator.newBuilder(2, "testApp").build(); // Full fetch with one item InstanceInfo first = instanceGen.first(); Applications initial = toApplications(first); when(requestHandler.getApplications(TEST_REMOTE_REGION)).thenReturn( anEurekaHttpResponse(200, initial).type(MediaType.APPLICATION_JSON_TYPE).build() ); EurekaClient client = discoveryClientResource.getClient(); assertThat(client.getApplications().getAppsHashCode(), is(equalTo("UP_1_"))); // Delta with one add InstanceInfo second = new InstanceInfo.Builder(instanceGen.take(1)).setStatus(InstanceStatus.DOWN).build(); Applications delta = toApplications(second); delta.setAppsHashCode("DOWN_1_UP_1_"); when(requestHandler.getDelta(TEST_REMOTE_REGION)).thenReturn( anEurekaHttpResponse(200, delta).type(MediaType.APPLICATION_JSON_TYPE).build() ); assertThat(discoveryClientResource.awaitCacheUpdate(5, TimeUnit.SECONDS), is(true)); assertThat(client.getApplications().getAppsHashCode(), is(equalTo("DOWN_1_UP_1_"))); }
/** * There is a bug, because of which remote registry data structures are not initialized during full registry fetch, only during delta. */ private void prepareRemoteRegionRegistry() throws Exception { Applications localApplications = InstanceInfoGenerator.newBuilder(4, "app1", "app2").build().toApplications(); Applications remoteApplications = InstanceInfoGenerator.newBuilder(4, "remote1", "remote2").withZone(TEST_REMOTE_ZONE).build().toApplications(); Applications allApplications = mergeApplications(localApplications, remoteApplications); // Load remote data in delta, to go around exiting bug in DiscoveryClient Applications delta = copyApplications(remoteApplications); delta.setAppsHashCode(allApplications.getAppsHashCode()); when(requestHandler.getApplications(TEST_REMOTE_REGION)).thenReturn( anEurekaHttpResponse(200, localApplications).type(MediaType.APPLICATION_JSON_TYPE).build() ); when(requestHandler.getDelta(TEST_REMOTE_REGION)).thenReturn( anEurekaHttpResponse(200, delta).type(MediaType.APPLICATION_JSON_TYPE).build() ); assertThat(discoveryClientResource.awaitCacheUpdate(5, TimeUnit.SECONDS), is(true)); } }
@Test public void testApplyDeltaWithBadInstanceInfoDataCenterInfoAsNull() throws Exception { InstanceInfoGenerator instanceGen = InstanceInfoGenerator.newBuilder(2, "testApp").build(); // Full fetch with one item InstanceInfo first = instanceGen.first(); Applications initial = toApplications(first); when(requestHandler.getApplications(TEST_REMOTE_REGION)).thenReturn( anEurekaHttpResponse(200, initial).type(MediaType.APPLICATION_JSON_TYPE).build() ); EurekaClient client = discoveryClientResource.getClient(); assertThat(client.getApplications().getAppsHashCode(), is(equalTo("UP_1_"))); // Delta with one add InstanceInfo second = new InstanceInfo.Builder(instanceGen.take(1)).setInstanceId("foo1").setStatus(InstanceStatus.DOWN).setDataCenterInfo(null).build(); InstanceInfo third = new InstanceInfo.Builder(instanceGen.take(1)).setInstanceId("foo2").setStatus(InstanceStatus.UP).setDataCenterInfo(new DataCenterInfo() { @Override public Name getName() { return null; } }).build(); Applications delta = toApplications(second, third); delta.setAppsHashCode("DOWN_1_UP_2_"); when(requestHandler.getDelta(TEST_REMOTE_REGION)).thenReturn( anEurekaHttpResponse(200, delta).type(MediaType.APPLICATION_JSON_TYPE).build() ); assertThat(discoveryClientResource.awaitCacheUpdate(5, TimeUnit.SECONDS), is(true)); assertThat(client.getApplications().getAppsHashCode(), is(equalTo("DOWN_1_UP_2_"))); }