@Override CountingMigrationAwareService createMigrationAwareService() { return new CountingMigrationAwareService(new MapMigrationAwareService(mapServiceContext)); }
private void removeRecordStoresHavingLesserBackupCountThan(int partitionId, int thresholdReplicaIndex) { if (thresholdReplicaIndex < 0) { mapServiceContext.removeRecordStoresFromPartitionMatchingWith(allRecordStores(), partitionId, false, true); } else { mapServiceContext.removeRecordStoresFromPartitionMatchingWith(lesserBackupMapsThen(thresholdReplicaIndex), partitionId, false, true); } }
@Override public void beforeMigration(PartitionMigrationEvent event) { if (isLocalPromotion(event)) { // It's a local partition promotion. We need to populate non-global indexes here since // there is no map replication performed in this case. Global indexes are populated // during promotion finalization phase. // 1. Defensively clear possible stale leftovers from the previous failed promotion attempt. clearNonGlobalIndexes(event); // 2. Populate non-global partitioned indexes. populateIndexes(event, TargetIndexes.NON_GLOBAL); } flushAndRemoveQueryCaches(event); }
@Override public void commitMigration(PartitionMigrationEvent event) { if (event.getMigrationEndpoint() == DESTINATION) { populateIndexes(event, TargetIndexes.GLOBAL); } else { depopulateIndexes(event); } if (SOURCE == event.getMigrationEndpoint()) { removeRecordStoresHavingLesserBackupCountThan(event.getPartitionId(), event.getNewReplicaIndex()); } PartitionContainer partitionContainer = mapServiceContext.getPartitionContainer(event.getPartitionId()); for (RecordStore recordStore : partitionContainer.getAllRecordStores()) { // in case the record store has been created without loading during migration trigger again // if loading has been already started this call will do nothing recordStore.startLoading(); } mapServiceContext.reloadOwnedPartitions(); removeOrRegenerateNearCacheUuid(event); }
@Override public void rollbackMigration(PartitionMigrationEvent event) { if (DESTINATION == event.getMigrationEndpoint()) { removeRecordStoresHavingLesserBackupCountThan(event.getPartitionId(), event.getCurrentReplicaIndex()); getMetaDataGenerator().removeUuidAndSequence(event.getPartitionId()); } mapServiceContext.reloadOwnedPartitions(); }
final long now = getNow(); addPartitionIndexes(recordStore, event.getPartitionId(), mapContainer.getPartitionIndexesToAdd());
private void depopulateIndexes(PartitionMigrationEvent event) { assert event.getMigrationEndpoint() == SOURCE; assert event.getNewReplicaIndex() != 0 : "Invalid migration event: " + event; if (event.getCurrentReplicaIndex() != 0) { // backup partitions have no indexes to depopulate return; } final long now = getNow(); final PartitionContainer container = mapServiceContext.getPartitionContainer(event.getPartitionId()); for (RecordStore recordStore : container.getMaps().values()) { final MapContainer mapContainer = mapServiceContext.getMapContainer(recordStore.getName()); final Indexes indexes = mapContainer.getIndexes(event.getPartitionId()); if (!indexes.hasIndex()) { // no indexes to work with continue; } final Iterator<Record> iterator = recordStore.iterator(now, false); while (iterator.hasNext()) { final Record record = iterator.next(); final Data key = record.getKey(); final Object value = Records.getValueOrCachedValue(record, serializationService); indexes.removeEntryIndex(key, value, Index.OperationSource.SYSTEM); } } }
private void removeOrRegenerateNearCacheUuid(PartitionMigrationEvent event) { if (SOURCE == event.getMigrationEndpoint()) { getMetaDataGenerator().removeUuidAndSequence(event.getPartitionId()); return; } if (DESTINATION == event.getMigrationEndpoint() && event.getNewReplicaIndex() != 0) { getMetaDataGenerator().regenerateUuid(event.getPartitionId()); return; } }
@Override public Operation prepareReplicationOperation(PartitionReplicationEvent event, Collection<ServiceNamespace> namespaces) { assert assertAllKnownNamespaces(namespaces); int partitionId = event.getPartitionId(); Operation operation = new MapReplicationOperation(containers[partitionId], namespaces, partitionId, event.getReplicaIndex()); operation.setService(mapServiceContext.getService()); operation.setNodeEngine(mapServiceContext.getNodeEngine()); return operation; }
private boolean assertAllKnownNamespaces(Collection<ServiceNamespace> namespaces) { for (ServiceNamespace namespace : namespaces) { assert isKnownServiceNamespace(namespace) : namespace + " is not a MapService namespace!"; } return true; }
/** * Flush and remove query cache on this source partition. */ private void flushAndRemoveQueryCaches(PartitionMigrationEvent event) { int partitionId = event.getPartitionId(); QueryCacheContext queryCacheContext = mapServiceContext.getQueryCacheContext(); PublisherContext publisherContext = queryCacheContext.getPublisherContext(); if (event.getMigrationEndpoint() == MigrationEndpoint.SOURCE) { flushAccumulator(publisherContext, partitionId); removeAccumulator(publisherContext, partitionId); return; } if (isLocalPromotion(event)) { removeAccumulator(publisherContext, partitionId); sendEndOfSequenceEvents(publisherContext, partitionId); return; } }
@Override public void commitMigration(PartitionMigrationEvent event) { if (event.getMigrationEndpoint() == DESTINATION) { populateIndexes(event, TargetIndexes.GLOBAL); } else { depopulateIndexes(event); } if (SOURCE == event.getMigrationEndpoint()) { removeRecordStoresHavingLesserBackupCountThan(event.getPartitionId(), event.getNewReplicaIndex()); } PartitionContainer partitionContainer = mapServiceContext.getPartitionContainer(event.getPartitionId()); for (RecordStore recordStore : partitionContainer.getAllRecordStores()) { // in case the record store has been created without loading during migration trigger again // if loading has been already started this call will do nothing recordStore.startLoading(); } mapServiceContext.reloadOwnedPartitions(); removeOrRegenerateNearCacheUuid(event); }
@Override public void rollbackMigration(PartitionMigrationEvent event) { if (DESTINATION == event.getMigrationEndpoint()) { removeRecordStoresHavingLesserBackupCountThan(event.getPartitionId(), event.getCurrentReplicaIndex()); getMetaDataGenerator().removeUuidAndSequence(event.getPartitionId()); } mapServiceContext.reloadOwnedPartitions(); }
private void depopulateIndexes(PartitionMigrationEvent event) { assert event.getMigrationEndpoint() == SOURCE; assert event.getNewReplicaIndex() != 0 : "Invalid migration event: " + event; if (event.getCurrentReplicaIndex() != 0) { // backup partitions have no indexes to depopulate return; } final long now = getNow(); final PartitionContainer container = mapServiceContext.getPartitionContainer(event.getPartitionId()); for (RecordStore recordStore : container.getMaps().values()) { final MapContainer mapContainer = mapServiceContext.getMapContainer(recordStore.getName()); final Indexes indexes = mapContainer.getIndexes(event.getPartitionId()); if (!indexes.haveAtLeastOneIndex()) { // no indexes to work with continue; } final InternalIndex[] indexesSnapshot = indexes.getIndexes(); final Iterator<Record> iterator = recordStore.iterator(now, false); while (iterator.hasNext()) { final Record record = iterator.next(); final Data key = record.getKey(); final Object value = Records.getValueOrCachedValue(record, serializationService); indexes.removeEntry(key, value, Index.OperationSource.SYSTEM); } Indexes.markPartitionAsUnindexed(event.getPartitionId(), indexesSnapshot); } }
private void removeOrRegenerateNearCacheUuid(PartitionMigrationEvent event) { if (SOURCE == event.getMigrationEndpoint()) { getMetaDataGenerator().removeUuidAndSequence(event.getPartitionId()); return; } if (DESTINATION == event.getMigrationEndpoint() && event.getNewReplicaIndex() != 0) { getMetaDataGenerator().regenerateUuid(event.getPartitionId()); return; } }
@Override public Operation prepareReplicationOperation(PartitionReplicationEvent event, Collection<ServiceNamespace> namespaces) { assert assertAllKnownNamespaces(namespaces); int partitionId = event.getPartitionId(); Operation operation = new MapReplicationOperation(containers[partitionId], namespaces, partitionId, event.getReplicaIndex()); operation.setService(mapServiceContext.getService()); operation.setNodeEngine(mapServiceContext.getNodeEngine()); return operation; }
private boolean assertAllKnownNamespaces(Collection<ServiceNamespace> namespaces) { for (ServiceNamespace namespace : namespaces) { assert isKnownServiceNamespace(namespace) : namespace + " is not a MapService namespace!"; } return true; }
/** * Flush and remove query cache on this source partition. */ private void flushAndRemoveQueryCaches(PartitionMigrationEvent event) { int partitionId = event.getPartitionId(); QueryCacheContext queryCacheContext = mapServiceContext.getQueryCacheContext(); PublisherContext publisherContext = queryCacheContext.getPublisherContext(); if (event.getMigrationEndpoint() == MigrationEndpoint.SOURCE) { flushAccumulator(publisherContext, partitionId); removeAccumulator(publisherContext, partitionId); return; } if (isLocalPromotion(event)) { removeAccumulator(publisherContext, partitionId); sendEndOfSequenceEvents(publisherContext, partitionId); return; } }
@Override public void beforeMigration(PartitionMigrationEvent event) { if (isLocalPromotion(event)) { // It's a local partition promotion. We need to populate non-global indexes here since // there is no map replication performed in this case. Global indexes are populated // during promotion finalization phase. // 1. Defensively clear possible stale leftovers from the previous failed promotion attempt. clearNonGlobalIndexes(event); // 2. Populate non-global partitioned indexes. populateIndexes(event, TargetIndexes.NON_GLOBAL); } flushAndRemoveQueryCaches(event); }
private void removeRecordStoresHavingLesserBackupCountThan(int partitionId, int thresholdReplicaIndex) { if (thresholdReplicaIndex < 0) { mapServiceContext.removeRecordStoresFromPartitionMatchingWith(allRecordStores(), partitionId, false, true); } else { mapServiceContext.removeRecordStoresFromPartitionMatchingWith(lesserBackupMapsThen(thresholdReplicaIndex), partitionId, false, true); } }