Search in sources :

Example 1 with UndeleteMessageFormatInputStream

use of com.github.ambry.messageformat.UndeleteMessageFormatInputStream in project ambry by linkedin.

the class ReplicationTestHelper method getUndeleteMessage.

public static ByteBuffer getUndeleteMessage(StoreKey id, short accountId, short containerId, short lifeVersion, long undeleteTimeMs) throws MessageFormatException, IOException {
    MessageFormatInputStream stream = new UndeleteMessageFormatInputStream(id, accountId, containerId, undeleteTimeMs, lifeVersion);
    byte[] message = Utils.readBytesFromStream(stream, (int) stream.getSize());
    return ByteBuffer.wrap(message);
}
Also used : DeleteMessageFormatInputStream(com.github.ambry.messageformat.DeleteMessageFormatInputStream) MessageFormatInputStream(com.github.ambry.messageformat.MessageFormatInputStream) PutMessageFormatInputStream(com.github.ambry.messageformat.PutMessageFormatInputStream) UndeleteMessageFormatInputStream(com.github.ambry.messageformat.UndeleteMessageFormatInputStream) TtlUpdateMessageFormatInputStream(com.github.ambry.messageformat.TtlUpdateMessageFormatInputStream) UndeleteMessageFormatInputStream(com.github.ambry.messageformat.UndeleteMessageFormatInputStream)

Example 2 with UndeleteMessageFormatInputStream

use of com.github.ambry.messageformat.UndeleteMessageFormatInputStream in project ambry by linkedin.

the class BlobStore method undelete.

@Override
public short undelete(MessageInfo info) throws StoreException {
    checkStarted();
    final Timer.Context context = metrics.undeleteResponse.time();
    // The lifeVersion from message info is -1 when the undelete method is invoked by frontend request, we have to
    // get the legit lifeVersion before we can write undelete record to log segment.
    short revisedLifeVersion = info.getLifeVersion();
    try {
        StoreKey id = info.getStoreKey();
        Offset indexEndOffsetBeforeCheck = index.getCurrentEndOffset();
        short lifeVersionFromMessageInfo = info.getLifeVersion();
        List<IndexValue> values = index.findAllIndexValuesForKey(id, new FileSpan(index.getStartOffset(), indexEndOffsetBeforeCheck));
        // Check if the undelete record is valid.
        index.validateSanityForUndelete(id, values, lifeVersionFromMessageInfo);
        IndexValue latestValue = values.get(0);
        IndexValue originalPut = values.get(values.size() - 1);
        if (!IndexValue.hasLifeVersion(revisedLifeVersion)) {
            revisedLifeVersion = (short) (latestValue.getLifeVersion() + 1);
        }
        MessageFormatInputStream stream = new UndeleteMessageFormatInputStream(id, info.getAccountId(), info.getContainerId(), info.getOperationTimeMs(), revisedLifeVersion);
        // Update info to add stream size;
        info = new MessageInfo(id, stream.getSize(), info.getAccountId(), info.getContainerId(), info.getOperationTimeMs(), revisedLifeVersion);
        ArrayList<MessageInfo> infoList = new ArrayList<>();
        infoList.add(info);
        MessageFormatWriteSet writeSet = new MessageFormatWriteSet(stream, infoList, false);
        if (!info.getStoreKey().isAccountContainerMatch(latestValue.getAccountId(), latestValue.getContainerId())) {
            if (config.storeValidateAuthorization) {
                throw new StoreException("UNDELETE authorization failure. Key: " + info.getStoreKey() + " Actually accountId: " + latestValue.getAccountId() + "Actually containerId: " + latestValue.getContainerId(), StoreErrorCodes.Authorization_Failure);
            } else {
                logger.warn("UNDELETE authorization failure. Key: {} Actually accountId: {} Actually containerId: {}", info.getStoreKey(), latestValue.getAccountId(), latestValue.getContainerId());
                metrics.undeleteAuthorizationFailureCount.inc();
            }
        }
        synchronized (storeWriteLock) {
            Offset currentIndexEndOffset = index.getCurrentEndOffset();
            if (!currentIndexEndOffset.equals(indexEndOffsetBeforeCheck)) {
                FileSpan fileSpan = new FileSpan(indexEndOffsetBeforeCheck, currentIndexEndOffset);
                IndexValue value = index.findKey(info.getStoreKey(), fileSpan, EnumSet.of(PersistentIndex.IndexEntryType.DELETE, PersistentIndex.IndexEntryType.UNDELETE));
                if (value != null) {
                    if (value.isUndelete() && value.getLifeVersion() == revisedLifeVersion) {
                        // Might get an concurrent undelete from both replication and frontend.
                        throw new IdUndeletedStoreException("Can't undelete id " + info.getStoreKey() + " in " + dataDir + " since concurrent operations", value.getLifeVersion());
                    } else {
                        logger.warn("Revised lifeVersion is " + revisedLifeVersion + " last value is " + value);
                        throw new StoreException("Cannot undelete id " + info.getStoreKey() + " since concurrent operation occurs", StoreErrorCodes.Life_Version_Conflict);
                    }
                }
            }
            Offset endOffsetOfLastMessage = log.getEndOffset();
            writeSet.writeTo(log);
            logger.trace("Store : {} undelete mark written to log", dataDir);
            FileSpan fileSpan = log.getFileSpanForMessage(endOffsetOfLastMessage, info.getSize());
            // we still use lifeVersion from message info here so that we can re-verify the sanity of undelete request in persistent index.
            IndexValue newUndelete = index.markAsUndeleted(info.getStoreKey(), fileSpan, null, info.getOperationTimeMs(), lifeVersionFromMessageInfo);
            blobStoreStats.handleNewUndeleteEntry(info.getStoreKey(), newUndelete, originalPut, latestValue);
        }
        onSuccess();
        return revisedLifeVersion;
    } catch (StoreException e) {
        if (e.getErrorCode() == StoreErrorCodes.IOError) {
            onError();
        }
        throw e;
    } catch (Exception e) {
        throw new StoreException("Unknown error while trying to undelete blobs from store " + dataDir, e, StoreErrorCodes.Unknown_Error);
    } finally {
        context.stop();
    }
}
Also used : ArrayList(java.util.ArrayList) DeleteMessageFormatInputStream(com.github.ambry.messageformat.DeleteMessageFormatInputStream) UndeleteMessageFormatInputStream(com.github.ambry.messageformat.UndeleteMessageFormatInputStream) MessageFormatInputStream(com.github.ambry.messageformat.MessageFormatInputStream) TtlUpdateMessageFormatInputStream(com.github.ambry.messageformat.TtlUpdateMessageFormatInputStream) UndeleteMessageFormatInputStream(com.github.ambry.messageformat.UndeleteMessageFormatInputStream) IOException(java.io.IOException) Timer(com.codahale.metrics.Timer) MessageFormatWriteSet(com.github.ambry.messageformat.MessageFormatWriteSet)

Example 3 with UndeleteMessageFormatInputStream

use of com.github.ambry.messageformat.UndeleteMessageFormatInputStream in project ambry by linkedin.

the class InMemoryStore method undelete.

@Override
public short undelete(MessageInfo info) throws StoreException {
    StoreKey key = info.getStoreKey();
    MessageInfo deleteInfo = getMessageInfo(key, messageInfos, true, false, false);
    if (info.getLifeVersion() == -1 && deleteInfo == null) {
        throw new StoreException("Key " + key + " not delete yet", StoreErrorCodes.ID_Not_Deleted);
    }
    short lifeVersion = info.getLifeVersion();
    MessageInfo latestInfo = deleteInfo;
    if (info.getLifeVersion() == MessageInfo.LIFE_VERSION_FROM_FRONTEND) {
        if (deleteInfo == null) {
            throw new StoreException("Id " + key + " requires first value to be a put and last value to be a delete", StoreErrorCodes.ID_Not_Deleted);
        }
        lifeVersion = (short) (deleteInfo.getLifeVersion() + 1);
    } else {
        if (deleteInfo == null) {
            latestInfo = getMergedMessageInfo(key, messageInfos);
        }
    }
    try {
        MessageFormatInputStream stream = new UndeleteMessageFormatInputStream(key, info.getAccountId(), info.getContainerId(), info.getOperationTimeMs(), lifeVersion);
        // Update info to add stream size;
        info = new MessageInfo(key, stream.getSize(), false, latestInfo.isTtlUpdated(), true, latestInfo.getExpirationTimeInMs(), null, info.getAccountId(), info.getContainerId(), info.getOperationTimeMs(), lifeVersion);
        MessageFormatWriteSet writeSet = new MessageFormatWriteSet(stream, Collections.singletonList(info), false);
        writeSet.writeTo(log);
        messageInfos.add(info);
        return lifeVersion;
    } catch (Exception e) {
        throw new StoreException("Unknown error while trying to undelete blobs from store", e, StoreErrorCodes.Unknown_Error);
    }
}
Also used : DeleteMessageFormatInputStream(com.github.ambry.messageformat.DeleteMessageFormatInputStream) UndeleteMessageFormatInputStream(com.github.ambry.messageformat.UndeleteMessageFormatInputStream) MessageFormatInputStream(com.github.ambry.messageformat.MessageFormatInputStream) TtlUpdateMessageFormatInputStream(com.github.ambry.messageformat.TtlUpdateMessageFormatInputStream) StoreKey(com.github.ambry.store.StoreKey) UndeleteMessageFormatInputStream(com.github.ambry.messageformat.UndeleteMessageFormatInputStream) StoreException(com.github.ambry.store.StoreException) IOException(java.io.IOException) MessageInfo(com.github.ambry.store.MessageInfo) StoreException(com.github.ambry.store.StoreException) MessageFormatWriteSet(com.github.ambry.messageformat.MessageFormatWriteSet)

Aggregations

DeleteMessageFormatInputStream (com.github.ambry.messageformat.DeleteMessageFormatInputStream)3 MessageFormatInputStream (com.github.ambry.messageformat.MessageFormatInputStream)3 TtlUpdateMessageFormatInputStream (com.github.ambry.messageformat.TtlUpdateMessageFormatInputStream)3 UndeleteMessageFormatInputStream (com.github.ambry.messageformat.UndeleteMessageFormatInputStream)3 MessageFormatWriteSet (com.github.ambry.messageformat.MessageFormatWriteSet)2 IOException (java.io.IOException)2 Timer (com.codahale.metrics.Timer)1 PutMessageFormatInputStream (com.github.ambry.messageformat.PutMessageFormatInputStream)1 MessageInfo (com.github.ambry.store.MessageInfo)1 StoreException (com.github.ambry.store.StoreException)1 StoreKey (com.github.ambry.store.StoreKey)1 ArrayList (java.util.ArrayList)1