Search in sources :

Example 1 with CommitLogReadException

use of org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException in project cassandra by apache.

the class CommitLogReader method readMutation.

/**
 * Deserializes and passes a Mutation to the ICommitLogReadHandler requested
 *
 * @param handler Handler that will take action based on deserialized Mutations
 * @param inputBuffer raw byte array w/Mutation data
 * @param size deserialized size of mutation
 * @param minPosition We need to suppress replay of mutations that are before the required minPosition
 * @param entryLocation filePointer offset of end of mutation within CommitLogSegment
 * @param desc CommitLogDescriptor being worked on
 */
@VisibleForTesting
protected void readMutation(CommitLogReadHandler handler, byte[] inputBuffer, int size, CommitLogPosition minPosition, final int entryLocation, final CommitLogDescriptor desc) throws IOException {
    // For now, we need to go through the motions of deserializing the mutation to determine its size and move
    // the file pointer forward accordingly, even if we're behind the requested minPosition within this SyncSegment.
    boolean shouldReplay = entryLocation > minPosition.position;
    final Mutation mutation;
    try (RebufferingInputStream bufIn = new DataInputBuffer(inputBuffer, 0, size)) {
        mutation = Mutation.serializer.deserialize(bufIn, desc.getMessagingVersion(), DeserializationHelper.Flag.LOCAL);
        // doublecheck that what we read is still] valid for the current schema
        for (PartitionUpdate upd : mutation.getPartitionUpdates()) upd.validate();
    } catch (UnknownTableException ex) {
        if (ex.id == null)
            return;
        AtomicInteger i = invalidMutations.get(ex.id);
        if (i == null) {
            i = new AtomicInteger(1);
            invalidMutations.put(ex.id, i);
        } else
            i.incrementAndGet();
        return;
    } catch (Throwable t) {
        JVMStabilityInspector.inspectThrowable(t);
        Path p = Files.createTempFile("mutation", "dat");
        try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(p))) {
            out.write(inputBuffer, 0, size);
        }
        // Checksum passed so this error can't be permissible.
        handler.handleUnrecoverableError(new CommitLogReadException(String.format("Unexpected error deserializing mutation; saved to %s.  " + "This may be caused by replaying a mutation against a table with the same name but incompatible schema.  " + "Exception follows: %s", p.toString(), t), CommitLogReadErrorReason.MUTATION_ERROR, false));
        return;
    }
    if (logger.isTraceEnabled())
        logger.trace("Read mutation for {}.{}: {}", mutation.getKeyspaceName(), mutation.key(), "{" + StringUtils.join(mutation.getPartitionUpdates().iterator(), ", ") + "}");
    if (shouldReplay)
        handler.handleMutation(mutation, size, entryLocation, desc);
}
Also used : Path(java.nio.file.Path) UnknownTableException(org.apache.cassandra.exceptions.UnknownTableException) DataInputBuffer(org.apache.cassandra.io.util.DataInputBuffer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CommitLogReadException(org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException) RebufferingInputStream(org.apache.cassandra.io.util.RebufferingInputStream) Mutation(org.apache.cassandra.db.Mutation) PartitionUpdate(org.apache.cassandra.db.partitions.PartitionUpdate) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 2 with CommitLogReadException

use of org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException in project cassandra by apache.

the class CommitLogReader method readSection.

/**
 * Reads a section of a file containing mutations
 *
 * @param handler Handler that will take action based on deserialized Mutations
 * @param reader FileDataInput / logical buffer containing commitlog mutations
 * @param minPosition CommitLogPosition indicating when we should start actively replaying mutations
 * @param end logical numeric end of the segment being read
 * @param statusTracker ReadStatusTracker with current state of mutation count, error state, etc
 * @param desc Descriptor for CommitLog serialization
 */
private void readSection(CommitLogReadHandler handler, FileDataInput reader, CommitLogPosition minPosition, int end, ReadStatusTracker statusTracker, CommitLogDescriptor desc) throws IOException {
    // seek rather than deserializing mutation-by-mutation to reach the desired minPosition in this SyncSegment
    if (desc.id == minPosition.segmentId && reader.getFilePointer() < minPosition.position)
        reader.seek(minPosition.position);
    while (statusTracker.shouldContinue() && reader.getFilePointer() < end && !reader.isEOF()) {
        long mutationStart = reader.getFilePointer();
        if (logger.isTraceEnabled())
            logger.trace("Reading mutation at {}", mutationStart);
        long claimedCRC32;
        int serializedSize;
        try {
            // read an EOF here
            if (end - reader.getFilePointer() < 4) {
                logger.trace("Not enough bytes left for another mutation in this CommitLog section, continuing");
                statusTracker.requestTermination();
                return;
            }
            // any of the reads may hit EOF
            serializedSize = reader.readInt();
            if (serializedSize == LEGACY_END_OF_SEGMENT_MARKER) {
                logger.trace("Encountered end of segment marker at {}", reader.getFilePointer());
                statusTracker.requestTermination();
                return;
            }
            // This prevents CRC by being fooled by special-case garbage in the file; see CASSANDRA-2128
            if (serializedSize < 10) {
                if (handler.shouldSkipSegmentOnError(new CommitLogReadException(String.format("Invalid mutation size %d at %d in %s", serializedSize, mutationStart, statusTracker.errorContext), CommitLogReadErrorReason.MUTATION_ERROR, statusTracker.tolerateErrorsInSection))) {
                    statusTracker.requestTermination();
                }
                return;
            }
            long claimedSizeChecksum = CommitLogFormat.calculateClaimedChecksum(reader, desc.version);
            checksum.reset();
            CommitLogFormat.updateChecksum(checksum, serializedSize, desc.version);
            if (checksum.getValue() != claimedSizeChecksum) {
                if (handler.shouldSkipSegmentOnError(new CommitLogReadException(String.format("Mutation size checksum failure at %d in %s", mutationStart, statusTracker.errorContext), CommitLogReadErrorReason.MUTATION_ERROR, statusTracker.tolerateErrorsInSection))) {
                    statusTracker.requestTermination();
                }
                return;
            }
            if (serializedSize > buffer.length)
                buffer = new byte[(int) (1.2 * serializedSize)];
            reader.readFully(buffer, 0, serializedSize);
            claimedCRC32 = CommitLogFormat.calculateClaimedCRC32(reader, desc.version);
        } catch (EOFException eof) {
            if (handler.shouldSkipSegmentOnError(new CommitLogReadException(String.format("Unexpected end of segment at %d in %s", mutationStart, statusTracker.errorContext), CommitLogReadErrorReason.EOF, statusTracker.tolerateErrorsInSection))) {
                statusTracker.requestTermination();
            }
            return;
        }
        checksum.update(buffer, 0, serializedSize);
        if (claimedCRC32 != checksum.getValue()) {
            if (handler.shouldSkipSegmentOnError(new CommitLogReadException(String.format("Mutation checksum failure at %d in %s", mutationStart, statusTracker.errorContext), CommitLogReadErrorReason.MUTATION_ERROR, statusTracker.tolerateErrorsInSection))) {
                statusTracker.requestTermination();
            }
            continue;
        }
        long mutationPosition = reader.getFilePointer();
        readMutation(handler, buffer, serializedSize, minPosition, (int) mutationPosition, desc);
        // are before this mark.
        if (mutationPosition >= minPosition.position)
            statusTracker.addProcessedMutation();
    }
}
Also used : CommitLogReadException(org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException)

Example 3 with CommitLogReadException

use of org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException in project cassandra by apache.

the class CommitLogReader method readCommitLogSegment.

/**
 * Reads mutations from file, handing them off to handler
 * @param handler Handler that will take action based on deserialized Mutations
 * @param file CommitLogSegment file to read
 * @param minPosition Optional minimum CommitLogPosition - all segments with id larger or matching w/greater position will be read
 * @param mutationLimit Optional limit on # of mutations to replay. Local ALL_MUTATIONS serves as marker to play all.
 * @param tolerateTruncation Whether or not we should allow truncation of this file or throw if EOF found
 *
 * @throws IOException
 */
public void readCommitLogSegment(CommitLogReadHandler handler, File file, CommitLogPosition minPosition, int mutationLimit, boolean tolerateTruncation) throws IOException {
    // just transform from the file name (no reading of headers) to determine version
    CommitLogDescriptor desc = CommitLogDescriptor.fromFileName(file.name());
    try (RandomAccessReader reader = RandomAccessReader.open(file)) {
        final long segmentIdFromFilename = desc.id;
        try {
            // The following call can either throw or legitimately return null. For either case, we need to check
            // desc outside this block and set it to null in the exception case.
            desc = CommitLogDescriptor.readHeader(reader, DatabaseDescriptor.getEncryptionContext());
        } catch (Exception e) {
            desc = null;
        }
        if (desc == null) {
            // don't care about whether or not the handler thinks we can continue. We can't w/out descriptor.
            // whether or not we can continue depends on whether this is the last segment
            handler.handleUnrecoverableError(new CommitLogReadException(String.format("Could not read commit log descriptor in file %s", file), CommitLogReadErrorReason.UNRECOVERABLE_DESCRIPTOR_ERROR, tolerateTruncation));
            return;
        }
        if (segmentIdFromFilename != desc.id) {
            if (handler.shouldSkipSegmentOnError(new CommitLogReadException(String.format("Segment id mismatch (filename %d, descriptor %d) in file %s", segmentIdFromFilename, desc.id, file), CommitLogReadErrorReason.RECOVERABLE_DESCRIPTOR_ERROR, false))) {
                return;
            }
        }
        if (shouldSkipSegmentId(file, desc, minPosition))
            return;
        CommitLogSegmentReader segmentReader;
        try {
            segmentReader = new CommitLogSegmentReader(handler, desc, reader, tolerateTruncation);
        } catch (Exception e) {
            handler.handleUnrecoverableError(new CommitLogReadException(String.format("Unable to create segment reader for commit log file: %s", e), CommitLogReadErrorReason.UNRECOVERABLE_UNKNOWN_ERROR, tolerateTruncation));
            return;
        }
        try {
            ReadStatusTracker statusTracker = new ReadStatusTracker(mutationLimit, tolerateTruncation);
            for (CommitLogSegmentReader.SyncSegment syncSegment : segmentReader) {
                // Only tolerate truncation if we allow in both global and segment
                statusTracker.tolerateErrorsInSection = tolerateTruncation & syncSegment.toleratesErrorsInSection;
                // Skip segments that are completely behind the desired minPosition
                if (desc.id == minPosition.segmentId && syncSegment.endPosition < minPosition.position)
                    continue;
                statusTracker.errorContext = String.format("Next section at %d in %s", syncSegment.fileStartPosition, desc.fileName());
                readSection(handler, syncSegment.input, minPosition, syncSegment.endPosition, statusTracker, desc);
                if (!statusTracker.shouldContinue())
                    break;
            }
        }// is wrapping an IOException.
         catch (RuntimeException re) {
            if (re.getCause() instanceof IOException)
                throw (IOException) re.getCause();
            throw re;
        }
        logger.info("Finished reading {}", file);
    }
}
Also used : RandomAccessReader(org.apache.cassandra.io.util.RandomAccessReader) CommitLogReadException(org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException) UnknownTableException(org.apache.cassandra.exceptions.UnknownTableException) ConfigurationException(org.apache.cassandra.exceptions.ConfigurationException) CommitLogReadException(org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException)

Aggregations

CommitLogReadException (org.apache.cassandra.db.commitlog.CommitLogReadHandler.CommitLogReadException)3 UnknownTableException (org.apache.cassandra.exceptions.UnknownTableException)2 VisibleForTesting (com.google.common.annotations.VisibleForTesting)1 Path (java.nio.file.Path)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 Mutation (org.apache.cassandra.db.Mutation)1 PartitionUpdate (org.apache.cassandra.db.partitions.PartitionUpdate)1 ConfigurationException (org.apache.cassandra.exceptions.ConfigurationException)1 DataInputBuffer (org.apache.cassandra.io.util.DataInputBuffer)1 RandomAccessReader (org.apache.cassandra.io.util.RandomAccessReader)1 RebufferingInputStream (org.apache.cassandra.io.util.RebufferingInputStream)1