Search in sources :

Example 1 with CacheFullException

use of io.pravega.segmentstore.storage.cache.CacheFullException in project pravega by pravega.

the class MemoryStateUpdater method addToReadIndex.

/**
 * Registers the given operation in the ReadIndex.
 *
 * @param operation The operation to register.
 * @throws CacheFullException If the operation could not be added to the {@link ReadIndex} due to the cache being
 * full and unable to evict anything to make room for more.
 * @throws ServiceHaltException If any unexpected exception occurred that prevented the operation from being
 * added to the {@link ReadIndex}. Unexpected exceptions are all exceptions other than those declared in this
 * method or that indicate we are shutting down or that the segment has been deleted.
 */
private void addToReadIndex(StorageOperation operation) throws ServiceHaltException, CacheFullException {
    try {
        if (operation instanceof StreamSegmentAppendOperation) {
            // Record a StreamSegmentAppendOperation. Just in case, we also support this type of operation, but we need to
            // log a warning indicating so. This means we do not optimize memory properly, and we end up storing data
            // in two different places.
            StreamSegmentAppendOperation appendOperation = (StreamSegmentAppendOperation) operation;
            this.readIndex.append(appendOperation.getStreamSegmentId(), appendOperation.getStreamSegmentOffset(), appendOperation.getData());
        } else if (operation instanceof MergeSegmentOperation) {
            // Record a MergeSegmentOperation. We call beginMerge here, and the StorageWriter will call completeMerge.
            MergeSegmentOperation mergeOperation = (MergeSegmentOperation) operation;
            this.readIndex.beginMerge(mergeOperation.getStreamSegmentId(), mergeOperation.getStreamSegmentOffset(), mergeOperation.getSourceSegmentId());
        } else {
            assert !(operation instanceof CachedStreamSegmentAppendOperation) : "attempted to add a CachedStreamSegmentAppendOperation to the ReadIndex";
        }
    } catch (ObjectClosedException | StreamSegmentNotExistsException ex) {
        // The Segment is in the process of being deleted. We usually end up in here because a concurrent delete
        // request has updated the metadata while we were executing.
        log.warn("Not adding operation '{}' to ReadIndex because it refers to a deleted StreamSegment.", operation);
    } catch (CacheFullException ex) {
        // Record the operation that we couldn't add and re-throw the exception as we cannot do anything about it here.
        log.warn("Not adding operation '{}' to ReadIndex because the Cache is full.", operation);
        throw ex;
    } catch (Exception ex) {
        throw new ServiceHaltException(String.format("Unable to add operation '%s' to ReadIndex.", operation), ex);
    }
}
Also used : ObjectClosedException(io.pravega.common.ObjectClosedException) ServiceHaltException(io.pravega.segmentstore.server.ServiceHaltException) CacheFullException(io.pravega.segmentstore.storage.cache.CacheFullException) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation) StreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation) MergeSegmentOperation(io.pravega.segmentstore.server.logs.operations.MergeSegmentOperation) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) ObjectClosedException(io.pravega.common.ObjectClosedException) StreamSegmentNotExistsException(io.pravega.segmentstore.contracts.StreamSegmentNotExistsException) ServiceHaltException(io.pravega.segmentstore.server.ServiceHaltException) CacheFullException(io.pravega.segmentstore.storage.cache.CacheFullException) DataCorruptionException(io.pravega.segmentstore.server.DataCorruptionException) CachedStreamSegmentAppendOperation(io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation)

Example 2 with CacheFullException

use of io.pravega.segmentstore.storage.cache.CacheFullException in project pravega by pravega.

the class AttributeIndexTests method testCacheWriteFailure.

/**
 * Tests the case when updates/reads fail due to a Cache failure (i.e., Cache Full). This should not interfere with
 * whatever operation triggered it and it should not affect ongoing operations on the index.
 */
@Test
public void testCacheWriteFailure() throws Exception {
    val exceptionMakers = Arrays.<Supplier<RuntimeException>>asList(IntentionalException::new, () -> new CacheFullException("intentional"));
    val attributeId = AttributeId.randomUUID();
    val attributeSegmentName = NameUtils.getAttributeSegmentName(SEGMENT_NAME);
    val initialValue = 0L;
    val finalValue = 1L;
    for (val exceptionMaker : exceptionMakers) {
        @Cleanup val context = new TestContext(DEFAULT_CONFIG);
        populateSegments(context);
        val idx = context.index.forSegment(SEGMENT_ID, TIMEOUT).join();
        // Populate the index with some initial value.
        val pointer1 = idx.update(Collections.singletonMap(attributeId, initialValue), TIMEOUT).join();
        // For the next insertion, simulate some cache exception.
        val insertInvoked = new AtomicBoolean(false);
        context.cacheStorage.beforeInsert = buffer -> {
            insertInvoked.set(true);
            throw exceptionMaker.get();
        };
        // Update the value. The cache insertion should fail because of the exception above.
        val pointer2 = idx.update(Collections.singletonMap(attributeId, finalValue), TIMEOUT).join();
        TestUtils.await(() -> context.storage.getStreamSegmentInfo(attributeSegmentName, TIMEOUT).join().getStartOffset() > pointer1, 5, TIMEOUT.toMillis());
        Assert.assertTrue(insertInvoked.get());
        AssertExtensions.assertGreaterThan("", pointer1, pointer2);
        // If the cache insertion would have actually failed, then the following read call would fail (it would try
        // to read from the truncated portion (that's why we have the asserts above).
        // First, setup a read interceptor to ensure we actually want to read from Storage.
        val readCount = new AtomicInteger(0);
        context.storage.readInterceptor = (segment, offset, length, wrappedStorage) -> {
            readCount.incrementAndGet();
            return CompletableFuture.completedFuture(null);
        };
        val value = idx.get(Collections.singletonList(attributeId), TIMEOUT).join();
        Assert.assertEquals(finalValue, (long) value.get(attributeId));
        AssertExtensions.assertGreaterThan("Expected Storage reads.", 0, readCount.get());
    }
}
Also used : lombok.val(lombok.val) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Supplier(java.util.function.Supplier) CacheFullException(io.pravega.segmentstore.storage.cache.CacheFullException) Cleanup(lombok.Cleanup) IntentionalException(io.pravega.test.common.IntentionalException) Test(org.junit.Test)

Example 3 with CacheFullException

use of io.pravega.segmentstore.storage.cache.CacheFullException in project pravega by pravega.

the class ContainerKeyCacheTests method testCacheUpdateFailure.

/**
 * Test a case when the cache storage throws errors while attempting to update.
 */
@Test
public void testCacheUpdateFailure() {
    val segmentId = 0;
    val offset1 = 0L;
    val offset2 = 1L;
    val spiedStorage = Mockito.spy(this.cacheStorage);
    @Cleanup val keyCache = new ContainerKeyCache(spiedStorage);
    val expectedResult = new HashMap<TestKey, CacheBucketOffset>();
    val keyHash = newSimpleHash();
    // Perform an initial insert and verify it.
    keyCache.updateSegmentIndexOffset(segmentId, offset1);
    val updateResult1 = keyCache.includeExistingKey(segmentId, keyHash, offset1);
    Assert.assertEquals("Unexpected result from includeExistingKey() for new insertion.", offset1, updateResult1);
    expectedResult.put(new TestKey(segmentId, keyHash), new CacheBucketOffset(offset1, false));
    checkCache(expectedResult, keyCache);
    // For the second insert, fail the cache update and verify that the whole entry has been evicted.
    val replaceAddress = new AtomicInteger(-1);
    Mockito.doAnswer(arg1 -> {
        replaceAddress.set(arg1.getArgument(0));
        throw new CacheFullException("cache full");
    }).when(spiedStorage).replace(Mockito.anyInt(), Mockito.any());
    val deleteAddress = new AtomicInteger(-1);
    Mockito.doAnswer(arg1 -> {
        deleteAddress.set(arg1.getArgument(0));
        return arg1.callRealMethod();
    }).when(spiedStorage).delete(Mockito.anyInt());
    val updateResult2 = keyCache.includeExistingKey(segmentId, keyHash, offset2);
    Assert.assertEquals("Unexpected result from includeExistingKey() for new insertion.", offset2, updateResult2);
    // Set the expected value to null - that indicates it shouldn't be in the cache.
    expectedResult.put(new TestKey(segmentId, keyHash), null);
    checkCache(expectedResult, keyCache);
    Assert.assertNotEquals("Replacement was not attempted.", -1, replaceAddress.get());
    Assert.assertEquals("Deletion was for wrong entry.", replaceAddress.get(), deleteAddress.get());
}
Also used : lombok.val(lombok.val) HashMap(java.util.HashMap) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CacheFullException(io.pravega.segmentstore.storage.cache.CacheFullException) Cleanup(lombok.Cleanup) Test(org.junit.Test)

Aggregations

CacheFullException (io.pravega.segmentstore.storage.cache.CacheFullException)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 Cleanup (lombok.Cleanup)2 lombok.val (lombok.val)2 Test (org.junit.Test)2 ObjectClosedException (io.pravega.common.ObjectClosedException)1 StreamSegmentNotExistsException (io.pravega.segmentstore.contracts.StreamSegmentNotExistsException)1 DataCorruptionException (io.pravega.segmentstore.server.DataCorruptionException)1 ServiceHaltException (io.pravega.segmentstore.server.ServiceHaltException)1 CachedStreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.CachedStreamSegmentAppendOperation)1 MergeSegmentOperation (io.pravega.segmentstore.server.logs.operations.MergeSegmentOperation)1 StreamSegmentAppendOperation (io.pravega.segmentstore.server.logs.operations.StreamSegmentAppendOperation)1 IntentionalException (io.pravega.test.common.IntentionalException)1 HashMap (java.util.HashMap)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 Supplier (java.util.function.Supplier)1