Search in sources :

Example 1 with SegmentToContainerMapper

use of io.pravega.shared.segment.SegmentToContainerMapper in project pravega by pravega.

the class StreamSegmentStoreTestBase method testSegmentRestoration.

/**
 * SegmentStore is used to create some segments, write data to them and let them flush to the storage.
 * This test only uses this storage to restore the container metadata segments in a new durable data log. Segment
 * properties are matched for verification after the restoration.
 * @throws Exception If an exception occurred.
 */
public void testSegmentRestoration() throws Exception {
    ArrayList<String> segmentNames;
    HashMap<String, ArrayList<String>> transactionsBySegment;
    HashMap<String, Long> lengths = new HashMap<>();
    ArrayList<ByteBuf> appendBuffers = new ArrayList<>();
    HashMap<String, ByteArrayOutputStream> segmentContents = new HashMap<>();
    try (val builder = createBuilder(0, false)) {
        val segmentStore = builder.createStreamSegmentService();
        segmentNames = createSegments(segmentStore);
        log.info("Created Segments: {}.", String.join(", ", segmentNames));
        transactionsBySegment = createTransactions(segmentNames, segmentStore);
        log.info("Created Transactions: {}.", transactionsBySegment.values().stream().flatMap(Collection::stream).collect(Collectors.joining(", ")));
        // Add some appends and seal segments
        ArrayList<String> segmentsAndTransactions = new ArrayList<>(segmentNames);
        transactionsBySegment.values().forEach(segmentsAndTransactions::addAll);
        appendData(segmentsAndTransactions, segmentContents, lengths, appendBuffers, segmentStore).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
        log.info("Finished appending data.");
        // Wait for flushing the segments to tier2
        waitForSegmentsInStorage(segmentNames, segmentStore).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
        log.info("Finished waiting for segments in Storage.");
        // Get the persistent storage from readOnlySegmentStore.
        @Cleanup Storage storage = builder.createStorageFactory().createStorageAdapter();
        storage.initialize(DEFAULT_EPOCH);
        // Create the environment for DebugSegmentContainer using the given storageFactory.
        @Cleanup DebugStreamSegmentContainerTests.TestContext context = DebugStreamSegmentContainerTests.createContext(executorService());
        OperationLogFactory localDurableLogFactory = new DurableLogFactory(DURABLE_LOG_CONFIG, context.dataLogFactory, executorService());
        // Start a debug segment container corresponding to each container Id and put it in the Hashmap with the Id.
        Map<Integer, DebugStreamSegmentContainer> debugStreamSegmentContainerMap = new HashMap<>();
        for (int containerId = 0; containerId < CONTAINER_COUNT; containerId++) {
            // Delete container metadata segment and attributes index segment corresponding to the container Id from the long term storage
            ContainerRecoveryUtils.deleteMetadataAndAttributeSegments(storage, containerId, TIMEOUT).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
            DebugStreamSegmentContainerTests.MetadataCleanupContainer localContainer = new DebugStreamSegmentContainerTests.MetadataCleanupContainer(containerId, CONTAINER_CONFIG, localDurableLogFactory, context.readIndexFactory, context.attributeIndexFactory, context.writerFactory, context.storageFactory, context.getDefaultExtensions(), executorService());
            Services.startAsync(localContainer, executorService()).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
            debugStreamSegmentContainerMap.put(containerId, localContainer);
        }
        // Restore all segments from the long term storage using debug segment container.
        ContainerRecoveryUtils.recoverAllSegments(storage, debugStreamSegmentContainerMap, executorService(), TIMEOUT);
        // Verify that segment details match post restoration.
        SegmentToContainerMapper segToConMapper = new SegmentToContainerMapper(CONTAINER_COUNT, true);
        for (String segment : segmentNames) {
            int containerId = segToConMapper.getContainerId(segment);
            SegmentProperties props = debugStreamSegmentContainerMap.get(containerId).getStreamSegmentInfo(segment, TIMEOUT).get(TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
            Assert.assertEquals("Segment length mismatch.", (long) lengths.get(segment), props.getLength());
        }
        for (int containerId = 0; containerId < CONTAINER_COUNT; containerId++) {
            debugStreamSegmentContainerMap.get(containerId).close();
        }
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ByteBuf(io.netty.buffer.ByteBuf) Cleanup(lombok.Cleanup) OperationLogFactory(io.pravega.segmentstore.server.OperationLogFactory) DurableLogFactory(io.pravega.segmentstore.server.logs.DurableLogFactory) SegmentToContainerMapper(io.pravega.shared.segment.SegmentToContainerMapper) lombok.val(lombok.val) ByteArrayOutputStream(java.io.ByteArrayOutputStream) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Storage(io.pravega.segmentstore.storage.Storage) DebugStreamSegmentContainer(io.pravega.segmentstore.server.containers.DebugStreamSegmentContainer) AtomicLong(java.util.concurrent.atomic.AtomicLong) Collection(java.util.Collection) AttributeUpdateCollection(io.pravega.segmentstore.contracts.AttributeUpdateCollection) DebugStreamSegmentContainerTests(io.pravega.segmentstore.server.containers.DebugStreamSegmentContainerTests) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties)

Example 2 with SegmentToContainerMapper

use of io.pravega.shared.segment.SegmentToContainerMapper in project pravega by pravega.

the class ContainerRecoveryUtils method updateCoreAttributes.

/**
 * Updates Core Attributes for all Segments for the given Containers.
 * This method iterates through all the back copies of Container Metadata Segments, interprets all entries as
 * Segment-SegmentInfo mappings and extracts the Core Attributes for each. These Core Attributes are then applied
 * to the same segments in the given Containers.
 * @param backUpMetadataSegments    A map of back copies of metadata segments along with their container Ids.
 * @param containersMap             A map of {@link DebugStreamSegmentContainer} instances with their container Ids.
 * @param executorService           A thread pool for execution.
 * @param timeout                   Timeout for the operation.
 * @throws InterruptedException     If the operation was interrupted while waiting.
 * @throws TimeoutException         If the timeout expired prior to being able to complete update attributes for all segments.
 * @throws ExecutionException       When execution of update attributes to all segments encountered an error.
 */
public static void updateCoreAttributes(Map<Integer, String> backUpMetadataSegments, Map<Integer, DebugStreamSegmentContainer> containersMap, ExecutorService executorService, Duration timeout) throws InterruptedException, ExecutionException, TimeoutException {
    Preconditions.checkState(backUpMetadataSegments.size() == containersMap.size(), "The number of " + "back-up metadata segments = %s and the number of containers = %s should match.", backUpMetadataSegments.size(), containersMap.size());
    val args = IteratorArgs.builder().fetchTimeout(timeout).build();
    SegmentToContainerMapper segToConMapper = new SegmentToContainerMapper(containersMap.size(), true);
    // Iterate through all back up metadata segments
    for (val backUpMetadataSegmentEntry : backUpMetadataSegments.entrySet()) {
        // Get the name of original metadata segment
        val metadataSegment = NameUtils.getMetadataSegmentName(backUpMetadataSegmentEntry.getKey());
        // Get the name of back up metadata segment
        val backUpMetadataSegment = backUpMetadataSegmentEntry.getValue();
        // Get the container for back up metadata segment
        val containerForBackUpMetadataSegment = containersMap.get(segToConMapper.getContainerId(backUpMetadataSegment));
        log.info("Back up container metadata segment name: {} and its container id: {}", backUpMetadataSegment, containerForBackUpMetadataSegment.getId());
        // Get the container for segments inside back up metadata segment
        val container = containersMap.get(backUpMetadataSegmentEntry.getKey());
        // Make sure the backup segment is registered as a table segment.
        val bmsInfo = containerForBackUpMetadataSegment.getStreamSegmentInfo(backUpMetadataSegment, timeout).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
        if (bmsInfo.getAttributes().getOrDefault(TableAttributes.INDEX_OFFSET, Attributes.NULL_ATTRIBUTE_VALUE) == Attributes.NULL_ATTRIBUTE_VALUE) {
            log.info("Back up container metadata segment name: {} does not have INDEX_OFFSET set; setting to 0 (forcing reindexing).", backUpMetadataSegment);
            containerForBackUpMetadataSegment.forSegment(backUpMetadataSegment, timeout).thenCompose(s -> s.updateAttributes(AttributeUpdateCollection.from(new AttributeUpdate(TableAttributes.INDEX_OFFSET, AttributeUpdateType.Replace, 0)), timeout)).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
            refreshDerivedProperties(backUpMetadataSegment, containerForBackUpMetadataSegment);
        }
        // Get the iterator to iterate through all segments in the back up metadata segment
        val tableExtension = containerForBackUpMetadataSegment.getExtension(ContainerTableExtension.class);
        val entryIterator = tableExtension.entryIterator(backUpMetadataSegment, args).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
        val futures = new ArrayList<CompletableFuture<Void>>();
        // Iterating through all segments in the back up metadata segment
        entryIterator.forEachRemaining(item -> {
            for (val entry : item.getEntries()) {
                val segmentInfo = MetadataStore.SegmentInfo.deserialize(entry.getValue());
                val properties = segmentInfo.getProperties();
                // skip, if this is original metadata segment
                if (properties.getName().equals(metadataSegment)) {
                    continue;
                }
                // Get the attributes for the current segment
                val attributeUpdates = properties.getAttributes().entrySet().stream().map(e -> new AttributeUpdate(e.getKey(), AttributeUpdateType.Replace, e.getValue())).collect(Collectors.toCollection(AttributeUpdateCollection::new));
                log.info("Segment Name: {} Attributes Updates: {}", properties.getName(), attributeUpdates);
                // Update attributes for the current segment
                futures.add(Futures.exceptionallyExpecting(container.updateAttributes(properties.getName(), attributeUpdates, timeout).thenRun(() -> refreshDerivedProperties(properties.getName(), container)), ex -> ex instanceof StreamSegmentNotExistsException, null));
            }
        }, executorService).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
        // Waiting for update attributes for all segments in each back up metadata segment.
        Futures.allOf(futures).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
    }
}
Also used : lombok.val(lombok.val) TableAttributes(io.pravega.segmentstore.contracts.tables.TableAttributes) Storage(io.pravega.segmentstore.storage.Storage) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) Date(java.util.Date) Exceptions(io.pravega.common.Exceptions) SimpleDateFormat(java.text.SimpleDateFormat) TimeoutException(java.util.concurrent.TimeoutException) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) IteratorArgs(io.pravega.segmentstore.contracts.tables.IteratorArgs) ArrayList(java.util.ArrayList) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) HashSet(java.util.HashSet) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) ByteArrayInputStream(java.io.ByteArrayInputStream) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Duration(java.time.Duration) Map(java.util.Map) ExecutorService(java.util.concurrent.ExecutorService) NameUtils(io.pravega.shared.NameUtils) Attributes(io.pravega.segmentstore.contracts.Attributes) Iterator(java.util.Iterator) lombok.val(lombok.val) Set(java.util.Set) Collectors(java.util.stream.Collectors) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Slf4j(lombok.extern.slf4j.Slf4j) AttributeUpdateCollection(io.pravega.segmentstore.contracts.AttributeUpdateCollection) ContainerTableExtension(io.pravega.segmentstore.server.tables.ContainerTableExtension) SegmentToContainerMapper(io.pravega.shared.segment.SegmentToContainerMapper) Preconditions(com.google.common.base.Preconditions) AttributeUpdateType(io.pravega.segmentstore.contracts.AttributeUpdateType) Futures(io.pravega.common.concurrent.Futures) NameUtils.getMetadataSegmentName(io.pravega.shared.NameUtils.getMetadataSegmentName) AttributeUpdateCollection(io.pravega.segmentstore.contracts.AttributeUpdateCollection) AttributeUpdate(io.pravega.segmentstore.contracts.AttributeUpdate) SegmentToContainerMapper(io.pravega.shared.segment.SegmentToContainerMapper) ArrayList(java.util.ArrayList) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)

Example 3 with SegmentToContainerMapper

use of io.pravega.shared.segment.SegmentToContainerMapper in project pravega by pravega.

the class ContainerRecoveryUtils method recoverAllSegments.

/**
 * Recovers Segments from the given Storage instance. This is done by:
 * 1. Listing all Segments from the given Storage instance and partitioning them by their assigned Container Id using
 * the standard {@link SegmentToContainerMapper}.
 * 2. Filtering out all shadow Segments (such as Attribute Segments).
 * 3. Registering all remaining (external) Segments to the owning Container's {@link MetadataStore}.
 *
 * The {@link DebugStreamSegmentContainer} instance(s) that are provided to this method may have some segments already
 * present in their respective {@link MetadataStore}.
 * After the method successfully completes, the following are true:
 * - Only the segments which exist in the {@link Storage} will remain in the Container's {@link MetadataStore}.
 * - If a Segment exists both in the Container's {@link MetadataStore} and in {@link Storage}, then the information
 * that exists in {@link Storage} (length, sealed) will prevail.
 *
 * If the method fails during execution, the appropriate exception is thrown and the Containers' {@link MetadataStore}
 * may be left in an inconsistent state.
 * @param storage                           A {@link Storage} instance that will be used to list segments from.
 * @param debugStreamSegmentContainersMap   A Map of Container Ids to {@link DebugStreamSegmentContainer} instances
 *                                          representing the containers that will be recovered.
 * @param executorService                   A thread pool for execution.
 * @param timeout                           Timeout for the operation.
 * @throws Exception                        If an exception occurred. This could be one of the following:
 *                                              * TimeoutException:     If the calls for computation(used in the method)
 *                                                                      didn't complete in time.
 *                                              * IOException     :     If a general IO exception occurred.
 */
public static void recoverAllSegments(Storage storage, Map<Integer, DebugStreamSegmentContainer> debugStreamSegmentContainersMap, ExecutorService executorService, Duration timeout) throws Exception {
    Preconditions.checkNotNull(storage);
    Preconditions.checkNotNull(executorService);
    Preconditions.checkNotNull(debugStreamSegmentContainersMap);
    Preconditions.checkArgument(debugStreamSegmentContainersMap.size() > 0, "There should be at least one " + "debug segment container instance.");
    int containerCount = debugStreamSegmentContainersMap.size();
    validateContainerIds(debugStreamSegmentContainersMap, containerCount);
    log.info("Recovery started for all containers...");
    // Get all segments in the metadata store for each debug segment container instance.
    Map<Integer, Set<String>> existingSegmentsMap = getExistingSegments(debugStreamSegmentContainersMap, executorService, timeout);
    SegmentToContainerMapper segToConMapper = new SegmentToContainerMapper(containerCount, true);
    Iterator<SegmentProperties> segmentIterator = storage.listSegments().join();
    Preconditions.checkNotNull(segmentIterator);
    // Iterate through all segments. Create each one of their using their respective debugSegmentContainer instance.
    ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();
    while (segmentIterator.hasNext()) {
        val currentSegment = segmentIterator.next();
        int containerId = segToConMapper.getContainerId(currentSegment.getName());
        String currentSegmentName = currentSegment.getName();
        // skip recovery if the segment is an attribute segment or metadata segment.
        if (NameUtils.isAttributeSegment(currentSegmentName) || getMetadataSegmentName(containerId).equals(currentSegmentName)) {
            continue;
        }
        existingSegmentsMap.get(containerId).remove(currentSegment.getName());
        futures.add(recoverSegment(debugStreamSegmentContainersMap.get(containerId), currentSegment, timeout));
    }
    Futures.allOf(futures).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
    futures.clear();
    // Delete segments which only exist in the container metadata, not in storage.
    for (val existingSegmentsSetEntry : existingSegmentsMap.entrySet()) {
        for (String segmentName : existingSegmentsSetEntry.getValue()) {
            log.info("Deleting segment '{}' as it is not in the storage.", segmentName);
            futures.add(debugStreamSegmentContainersMap.get(existingSegmentsSetEntry.getKey()).deleteStreamSegment(segmentName, timeout));
        }
    }
    Futures.allOf(futures).get(timeout.toMillis(), TimeUnit.MILLISECONDS);
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) lombok.val(lombok.val) CompletableFuture(java.util.concurrent.CompletableFuture) HashSet(java.util.HashSet) Set(java.util.Set) SegmentToContainerMapper(io.pravega.shared.segment.SegmentToContainerMapper) ArrayList(java.util.ArrayList) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties)

Example 4 with SegmentToContainerMapper

use of io.pravega.shared.segment.SegmentToContainerMapper in project pravega by pravega.

the class DebugStreamSegmentContainerTests method testDataRecoveryStorageLevel.

/**
 * Use a storage instance to create segments. Lists the segments from the storage and and then recreates them using
 * debug segment containers. Before re-creating(or registering), the segments are mapped to their respective debug
 * segment container. Once registered, segment's properties are matched to verify if the test was successful or not.
 */
@Test
public void testDataRecoveryStorageLevel() throws Exception {
    // Segments are mapped to four different containers.
    int containerCount = 4;
    int segmentsToCreateCount = 50;
    // Create a storage.
    @Cleanup val baseStorage = new InMemoryStorage();
    @Cleanup val s = new RollingStorage(baseStorage, new SegmentRollingPolicy(1));
    s.initialize(1);
    log.info("Created a storage instance");
    // Record details(name, container Id & sealed status) of each segment to be created.
    Set<String> sealedSegments = new HashSet<>();
    byte[] data = "data".getBytes();
    SegmentToContainerMapper segToConMapper = new SegmentToContainerMapper(containerCount, true);
    Map<Integer, ArrayList<String>> segmentByContainers = new HashMap<>();
    // Create segments and get their container Ids, sealed status and names to verify.
    for (int i = 0; i < segmentsToCreateCount; i++) {
        String segmentName = "segment-" + RANDOM.nextInt();
        // Use segmentName to map to different containers.
        int containerId = segToConMapper.getContainerId(segmentName);
        ArrayList<String> segmentsList = segmentByContainers.get(containerId);
        if (segmentsList == null) {
            segmentsList = new ArrayList<>();
            segmentByContainers.put(containerId, segmentsList);
        }
        segmentByContainers.get(containerId).add(segmentName);
        // Create segments, write data and randomly seal some of them.
        val wh1 = s.create(segmentName);
        // Write data.
        s.write(wh1, 0, new ByteArrayInputStream(data), data.length);
        if (RANDOM.nextBoolean()) {
            s.seal(wh1);
            sealedSegments.add(segmentName);
        }
    }
    log.info("Created some segments using the storage.");
    @Cleanup TestContext context = createContext(executorService());
    OperationLogFactory localDurableLogFactory = new DurableLogFactory(DEFAULT_DURABLE_LOG_CONFIG, context.dataLogFactory, executorService());
    Map<Integer, DebugStreamSegmentContainer> debugStreamSegmentContainerMap = new HashMap<>();
    log.info("Start a debug segment container corresponding to each container id.");
    for (int containerId = 0; containerId < containerCount; containerId++) {
        MetadataCleanupContainer localContainer = new MetadataCleanupContainer(containerId, CONTAINER_CONFIG, localDurableLogFactory, context.readIndexFactory, context.attributeIndexFactory, context.writerFactory, context.storageFactory, context.getDefaultExtensions(), executorService());
        Services.startAsync(localContainer, executorService()).join();
        debugStreamSegmentContainerMap.put(containerId, localContainer);
    }
    log.info("Recover all segments using the storage and debug segment containers.");
    recoverAllSegments(new AsyncStorageWrapper(s, executorService()), debugStreamSegmentContainerMap, executorService(), TIMEOUT);
    // Re-create all segments which were listed.
    for (int containerId = 0; containerId < containerCount; containerId++) {
        for (String segment : segmentByContainers.get(containerId)) {
            SegmentProperties props = debugStreamSegmentContainerMap.get(containerId).getStreamSegmentInfo(segment, TIMEOUT).join();
            Assert.assertEquals("Segment length mismatch.", data.length, props.getLength());
            Assert.assertEquals("Sealed status of the segment don't match.", sealedSegments.contains(segment), props.isSealed());
        }
        debugStreamSegmentContainerMap.get(containerId).close();
    }
}
Also used : SegmentRollingPolicy(io.pravega.segmentstore.storage.SegmentRollingPolicy) HashMap(java.util.HashMap) RollingStorage(io.pravega.segmentstore.storage.rolling.RollingStorage) ArrayList(java.util.ArrayList) Cleanup(lombok.Cleanup) OperationLogFactory(io.pravega.segmentstore.server.OperationLogFactory) InMemoryStorage(io.pravega.segmentstore.storage.mocks.InMemoryStorage) DurableLogFactory(io.pravega.segmentstore.server.logs.DurableLogFactory) SegmentToContainerMapper(io.pravega.shared.segment.SegmentToContainerMapper) AsyncStorageWrapper(io.pravega.segmentstore.storage.AsyncStorageWrapper) HashSet(java.util.HashSet) lombok.val(lombok.val) ByteArrayInputStream(java.io.ByteArrayInputStream) SegmentProperties(io.pravega.segmentstore.contracts.SegmentProperties) Test(org.junit.Test)

Aggregations

SegmentProperties (io.pravega.segmentstore.contracts.SegmentProperties)4 SegmentToContainerMapper (io.pravega.shared.segment.SegmentToContainerMapper)4 ArrayList (java.util.ArrayList)4 lombok.val (lombok.val)4 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)3 AttributeUpdateCollection (io.pravega.segmentstore.contracts.AttributeUpdateCollection)2 OperationLogFactory (io.pravega.segmentstore.server.OperationLogFactory)2 DurableLogFactory (io.pravega.segmentstore.server.logs.DurableLogFactory)2 Storage (io.pravega.segmentstore.storage.Storage)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 Set (java.util.Set)2 CompletableFuture (java.util.concurrent.CompletableFuture)2 Preconditions (com.google.common.base.Preconditions)1 ByteBuf (io.netty.buffer.ByteBuf)1 Exceptions (io.pravega.common.Exceptions)1 Futures (io.pravega.common.concurrent.Futures)1 AttributeUpdate (io.pravega.segmentstore.contracts.AttributeUpdate)1 AttributeUpdateType (io.pravega.segmentstore.contracts.AttributeUpdateType)1