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);
}
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();
}
}
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);
}
}
Aggregations