Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
package org.apache.iotdb.db.i18n;

public final class DataNodePipeMessages {
public static final String LOG_SUBSCRIPTION_REPLAY_HAS_MADE_NO_CURSOR_PROGRESS_FOR_ARG_MS_ARG_INSPECT_PREFETCH_WORKER_STACKS_AND_WAL_I_O_FAE1F64B =
"Subscription replay has made no cursor progress for {} ms: {}. Inspect prefetch worker stacks and WAL I/O.";
public static final String LOG_SUBSCRIPTION_REPLAY_STALLED_FOR_ARG_MS_ARG_DIAGNOSTICS_ARG_INSPECT_PREFETCH_WORKER_STACKS_AND_WAL_I_O_CB012F98 =
"Subscription replay stalled for {} ms: {}; diagnostics={}. Inspect prefetch worker stacks and WAL I/O.";

public static final String
LOG_SUBSCRIPTION_PREFETCH_ROUND_STARTING_FOR_ARG_ACTIVE_ARG_INITIALIZED_ARG_CLOSED_ARG_PENDINGENTRIES_ARG_PREFETCHEDEVENTS_ARG_INFLIGHTEVENTS_ARG_NEXTREADSEARCHINDEX_ARG_F75FF2CD =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

public final class StorageEngineMessages {

public static final String LOG_REBUILT_UNREADABLE_WAL_FOOTER_FILE_ARG_VERSION_ARG_ORIGINALFILEBYTES_ARG_WRITERPROGRESS_ARG_1DBF836E =
"Rebuilt unreadable WAL footer: file={}, version={}, originalFileBytes={}, writerProgress={}.";

public static final String MESSAGE_LOAD_TSFILE_SLICE_BODY_IS_NULL_OR_EMPTY_2A65366C =
"Load TsFile slice body is null or empty";
public static final String MESSAGE_INVALID_LOAD_TSFILE_SLICE_METADATA_SLICECOUNT_ARG_ORIGINBODYSIZE_ARG_379BF1B8 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
package org.apache.iotdb.db.i18n;

public final class DataNodePipeMessages {
public static final String LOG_SUBSCRIPTION_REPLAY_HAS_MADE_NO_CURSOR_PROGRESS_FOR_ARG_MS_ARG_INSPECT_PREFETCH_WORKER_STACKS_AND_WAL_I_O_FAE1F64B =
"订阅回放游标已连续 {} ms 未推进:{}。请检查预取工作线程栈和 WAL I/O。";
public static final String LOG_SUBSCRIPTION_REPLAY_STALLED_FOR_ARG_MS_ARG_DIAGNOSTICS_ARG_INSPECT_PREFETCH_WORKER_STACKS_AND_WAL_I_O_CB012F98 =
"订阅回放已停滞 {} ms:{};diagnostics={}。请检查预取工作线程栈和 WAL I/O。";

public static final String
LOG_SUBSCRIPTION_PREFETCH_ROUND_STARTING_FOR_ARG_ACTIVE_ARG_INITIALIZED_ARG_CLOSED_ARG_PENDINGENTRIES_ARG_PREFETCHEDEVENTS_ARG_INFLIGHTEVENTS_ARG_NEXTREADSEARCHINDEX_ARG_F75FF2CD =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

public final class StorageEngineMessages {

public static final String LOG_REBUILT_UNREADABLE_WAL_FOOTER_FILE_ARG_VERSION_ARG_ORIGINALFILEBYTES_ARG_WRITERPROGRESS_ARG_1DBF836E =
"已重建不可读的 WAL footer:file={},version={},originalFileBytes={},writerProgress={}。";

public static final String MESSAGE_LOAD_TSFILE_SLICE_BODY_IS_NULL_OR_EMPTY_2A65366C =
"Load TsFile 分片内容为 null 或为空";
public static final String MESSAGE_INVALID_LOAD_TSFILE_SLICE_METADATA_SLICECOUNT_ARG_ORIGINBODYSIZE_ARG_379BF1B8 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -312,6 +313,41 @@ public List<Long> getLocalSeqs() {
return localSeqs;
}

/** Diagnostic summary for an abnormal footer recovery, never for the normal write path. */
public Map<String, Object> getWriterProgressDiagnostics() {
final Map<String, Object> result = new LinkedHashMap<>();
final int entries = buffersSize.size();
final int progressEntries =
Math.min(
entries, Math.min(physicalTimes.size(), Math.min(nodeIds.size(), localSeqs.size())));
int attributedEntries = 0;
int defaultLocalProgressEntries = 0;
final List<String> unattributedSamples = new ArrayList<>();
for (int i = 0; i < progressEntries; i++) {
final long physicalTime = physicalTimes.get(i);
final int nodeId = nodeIds.get(i);
final long localSeq = localSeqs.get(i);
if (nodeId >= 0 && physicalTime >= 0 && localSeq >= 0) {
attributedEntries++;
} else {
if (unattributedSamples.size() < 4) {
unattributedSamples.add(i + ":(" + physicalTime + "," + nodeId + "," + localSeq + ")");
}
if (nodeId < 0 && physicalTime == 0 && localSeq >= 0) {
defaultLocalProgressEntries++;
}
}
}
result.put("entryCount", entries);
result.put("firstSearchIndex", firstSearchIndex);
result.put("attributedProgressEntries", attributedEntries);
result.put("unattributedProgressEntries", progressEntries - attributedEntries);
result.put("missingProgressEntries", entries - progressEntries);
result.put("defaultLocalProgressEntries", defaultLocalProgressEntries);
result.put("unattributedSamples", unattributedSamples);
return result;
}

private int getNodeIdOverrideCount() {
final short defaultNodeId = computeDefaultNodeId();
int count = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,16 @@

package org.apache.iotdb.db.storageengine.dataregion.wal.recover;

import org.apache.iotdb.db.i18n.StorageEngineMessages;
import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntryType;
import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALByteBufReader;
import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALFileVersion;
import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALMetaData;
import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALWriter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
Expand All @@ -38,6 +42,7 @@

/** Check whether the wal file is broken and repair it. */
public class WALRepairWriter {
private static final Logger LOGGER = LoggerFactory.getLogger(WALRepairWriter.class);
private final File logFile;

public WALRepairWriter(File logFile) {
Expand All @@ -63,6 +68,7 @@ public boolean repair(WALMetaData metaData) throws IOException {
quarantine();
return false;
}
final long originalFileBytes = logFile.length();
// A channel offset may include a partially read entry in the same compressed segment. Rebuild
// complete entries in a temporary file instead of truncating at a read-ahead offset. Publish
// only after every entry and the new footer have been written and forced successfully.
Expand Down Expand Up @@ -111,6 +117,15 @@ public boolean repair(WALMetaData metaData) throws IOException {
} finally {
Files.deleteIfExists(repaired);
}
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(
StorageEngineMessages
.LOG_REBUILT_UNREADABLE_WAL_FOOTER_FILE_ARG_VERSION_ARG_ORIGINALFILEBYTES_ARG_WRITERPROGRESS_ARG_1DBF836E,
logFile,
version,
originalFileBytes,
metaData.getWriterProgressDiagnostics());
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ public class ConsensusPrefetchingQueue {
private long lastReplayProgressNanos;
private boolean replayStallWarningLogged;
private long lastReplayStallWarningNanos;
private WriterFrontier lastBlockedWriterFrontier;
private boolean lastWriterBarrierInOrderedReplay;

private volatile String lastConsumerId = "";

Expand Down Expand Up @@ -1687,6 +1689,7 @@ public SubscriptionEvent pollTablets(
private static final long PREFETCH_STATS_LOG_INTERVAL_MS = 5_000L;
private static final long REPLAY_STALL_WARNING_THRESHOLD_NANOS = TimeUnit.SECONDS.toNanos(60L);
private static final long REPLAY_STALL_WARNING_INTERVAL_NANOS = TimeUnit.SECONDS.toNanos(30L);
private static final int MAX_REPLAY_DIAGNOSTIC_WRITERS = 4;

private static final long SLOW_PREFETCH_ROUND_THRESHOLD_MS = 10_000L;

Expand Down Expand Up @@ -1800,6 +1803,8 @@ private PrefetchRoundResult drivePrefetchOnceUnderReadLock() {
getPrefetchDurationMs());
}
logPeriodicStatsIfNecessary();
// Preserve the previous round's actual ordering decision until the stall reporter sees it.
lastBlockedWriterFrontier = null;

final long currentSeekGeneration = seekGeneration.get();
if (currentSeekGeneration != observedSeekGeneration) {
Expand Down Expand Up @@ -2067,6 +2072,8 @@ private PrefetchRoundResult driveOrderedWriterReplay(
}
final WriterFrontier next = frontiers.peek();
if (Objects.isNull(next) || next.isBarrier) {
lastBlockedWriterFrontier = next;
lastWriterBarrierInOrderedReplay = true;
break;
}
final PreparedEntry buffered = peekRealtimeEntry(next.writerNodeId);
Expand Down Expand Up @@ -2393,19 +2400,138 @@ private void reportReplayStallIfNecessary(final long nowNanos) {
final long stalledNanos = nowNanos - lastReplayProgressNanos;
if (stalledNanos >= REPLAY_STALL_WARNING_THRESHOLD_NANOS
&& (!replayStallWarningLogged
|| nowNanos - lastReplayStallWarningNanos >= REPLAY_STALL_WARNING_INTERVAL_NANOS)) {
|| nowNanos - lastReplayStallWarningNanos >= REPLAY_STALL_WARNING_INTERVAL_NANOS)
&& LOGGER.isWarnEnabled()) {
LOGGER.warn(
DataNodePipeMessages
.LOG_SUBSCRIPTION_REPLAY_HAS_MADE_NO_CURSOR_PROGRESS_FOR_ARG_MS_ARG_INSPECT_PREFETCH_WORKER_STACKS_AND_WAL_I_O_FAE1F64B,
.LOG_SUBSCRIPTION_REPLAY_STALLED_FOR_ARG_MS_ARG_DIAGNOSTICS_ARG_INSPECT_PREFETCH_WORKER_STACKS_AND_WAL_I_O_CB012F98,
TimeUnit.NANOSECONDS.toMillis(stalledNanos),
this);
this,
getReplayStallDiagnostics());
lastReplayStallWarningNanos = nowNanos;
replayStallWarningLogged = true;
}
}

private Map<String, Object> getReplayStallDiagnostics() {
// Only called for the throttled stall warning, on the serialized prefetch worker. Do not
// refresh frontiers, probe WAL readers, or dump requests/Tablets while taking this snapshot.
final Map<String, Object> result = new LinkedHashMap<>();
result.put("runtimeVersion", runtimeVersion);
result.put("admissionBlockReason", realtimeAdmissionBlockReason);
result.put("memoryBlockReason", memoryBlockReason);
result.put("prefetchLimitReached", hasReachedPrefetchLimit());
result.put("lingerEntryCount", lingerBatch.entryCount);
result.put("lastBlockedFrontier", lastBlockedWriterFrontier);
result.put(
"lastBarrierInOrderedReplay",
Objects.nonNull(lastBlockedWriterFrontier) ? lastWriterBarrierInOrderedReplay : null);
final Map<Integer, SafeFrontier> safeFrontiers =
serverImpl.getWriterSafeFrontierTracker().snapshotSafeFrontiers();
result.put("activeWriterCount", activeWriterNodeIds.size());
result.put("activeWriters", sampleWriterDiagnostics(activeWriterNodeIds, safeFrontiers));
result.put("realtimeWriterCount", realtimeEntriesByWriter.size());
result.put(
"realtimeWriters",
sampleWriterDiagnostics(realtimeEntriesByWriter.keySet(), safeFrontiers));
result.put("orderedWriterCount", orderedWriterReplay.size());
result.put(
"orderedWriters", sampleWriterDiagnostics(orderedWriterReplay.keySet(), safeFrontiers));
final RegionProgress committed =
commitManager.getCommittedRegionProgress(consumerGroupId, topicName, consensusGroupId);
result.put("committedWriterCount", committed.getWriterPositions().size());
final List<String> committedSamples = new ArrayList<>();
for (final Map.Entry<WriterId, WriterProgress> entry :
committed.getWriterPositions().entrySet()) {
if (committedSamples.size() >= MAX_REPLAY_DIAGNOSTIC_WRITERS) {
break;
}
committedSamples.add(entry.toString());
}
result.put("committedWriters", committedSamples);
result.put("committedRetainedMinVersionId", committedRetainedMinVersionId);
final WalFileCommitRequirement requirement =
walFileCommitRequirements.get(committedRetainedMinVersionId);
result.put(
"retentionContainsUnsupportedProgress",
Objects.nonNull(requirement) ? requirement.containsUnsupportedProgress : null);
if (consensusReqReader instanceof WALNode) {
result.put("walDirectory", ((WALNode) consensusReqReader).getLogDirectory());
}
result.put(
"walScanState",
Objects.nonNull(subscriptionWALIterator)
? subscriptionWALIterator.getDiagnosticState()
: null);
return result;
}

private List<Map<String, Object>> sampleWriterDiagnostics(
final Set<Integer> writerNodeIds, final Map<Integer, SafeFrontier> safeFrontiers) {
final List<Map<String, Object>> samples = new ArrayList<>();
final Set<Integer> sampledWriterNodeIds = new LinkedHashSet<>();
// Keep unknown progress and the actual blocker visible even when other writers fill the cap.
if (writerNodeIds.contains(-1)) {
sampledWriterNodeIds.add(-1);
}
if (Objects.nonNull(lastBlockedWriterFrontier)
&& writerNodeIds.contains(lastBlockedWriterFrontier.writerNodeId)) {
sampledWriterNodeIds.add(lastBlockedWriterFrontier.writerNodeId);
}
for (final int writerNodeId : writerNodeIds) {
if (sampledWriterNodeIds.size() >= MAX_REPLAY_DIAGNOSTIC_WRITERS) {
break;
}
sampledWriterNodeIds.add(writerNodeId);
}
for (final int writerNodeId : sampledWriterNodeIds) {
final Map<String, Object> sample = new LinkedHashMap<>();
sample.put("writerNodeId", writerNodeId);
final WriterState state = writerStates.get(writerNodeId);
sample.put("effectiveSafePt", Objects.nonNull(state) ? state.effectiveSafePt : null);
sample.put("closed", Objects.nonNull(state) ? state.closed : null);
final SafeFrontier safeFrontier = safeFrontiers.get(writerNodeId);
if (Objects.nonNull(safeFrontier)) {
sample.put("trackerSafePt", safeFrontier.getPhysicalTime());
sample.put("trackerAppliedLocalSeq", safeFrontier.getLocalSeq());
}
final PreparedEntry buffered = peekRealtimeEntry(writerNodeId);
if (Objects.nonNull(buffered)) {
sample.put("bufferedHead", buffered.getOrderingKey());
sample.put("bufferedSearchIndex", buffered.searchIndex);
sample.put("bufferedEntryCount", realtimeEntriesByWriter.get(writerNodeId).size());
}
sample.put("materializedProgress", materializedProgressByWriter.get(writerNodeId));
sample.put(
"recoveryProgress",
recoveryWriterProgressByWriter.get(
new WriterId(consensusGroupId.toString(), writerNodeId)));
final WriterReplayState replay = orderedWriterReplay.get(writerNodeId);
if (Objects.nonNull(replay)) {
sample.put("consumedLocalSeq", replay.consumedLocalSeq);
sample.put("caughtUp", replay.caughtUp);
sample.put("fromPending", replay.fromPending);
if (Objects.nonNull(replay.head)) {
sample.put(
"rawHead",
new OrderingKey(
replay.head.getPhysicalTime(),
replay.head.getNodeId(),
replay.head.getProgressLocalSeq()));
sample.put("rawSearchIndex", replay.head.getSearchIndex());
}
sample.put(
"walScanState",
Objects.nonNull(replay.iterator) ? replay.iterator.getDiagnosticState() : null);
}
samples.add(sample);
}
return samples;
}

private void resetRoundStateForSeek(final long newSeekGeneration) {
replayProgressObserved = false;
lastBlockedWriterFrontier = null;
restorePendingSubscriptionWalCursor(newSeekGeneration);
discardRealtimeEntries();
discardBatch(lingerBatch);
Expand Down Expand Up @@ -3734,6 +3860,8 @@ private <T extends WriterBufferedEntry> boolean drainWriterEntries(
}
final WriterFrontier frontier = frontiers.peek();
if (Objects.isNull(frontier) || frontier.isBarrier) {
lastBlockedWriterFrontier = frontier;
lastWriterBarrierInOrderedReplay = false;
return true;
}
final T writerHead = headSupplier.apply(frontier.writerNodeId);
Expand Down Expand Up @@ -6204,6 +6332,17 @@ private static WriterFrontier forBarrier(final int writerNodeId, final long effe
writerNodeId, new OrderingKey(effectiveSafePt, Integer.MIN_VALUE, Long.MIN_VALUE), true);
}

@Override
public String toString() {
return "WriterFrontier{writerNodeId="
+ writerNodeId
+ ", orderingKey="
+ orderingKey
+ ", barrier="
+ isBarrier
+ '}';
}

@Override
public int compareTo(final WriterFrontier other) {
int cmp = orderingKey.compareTo(other.orderingKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,28 @@ public String toString() {
+ "]";
}

String getDiagnosticState() {
// Called only by the throttled queue stall warning; never read entry bodies or advance here.
return this
+ "[file="
+ currentReaderFile
+ ", liveSnapshot="
+ currentReaderUsesLiveSnapshot
+ ", metadataRecoveredFromEntries="
+ (currentReader != null && currentReader.getMetaData().isRecoveredFromEntries())
+ ", pendingProgress=("
+ pendingPhysicalTime
+ ","
+ pendingNodeId
+ ","
+ pendingLocalSeq
+ "), pendingSearchIndex="
+ pendingSearchIndex
+ ", pendingFragments="
+ pendingRequests.size()
+ "]";
}

String getSkippedBrokenWalFileDetails(final int firstFileIndex) {
final int firstAvailableIndex =
getSkippedBrokenWalFileCount() - skippedBrokenWalFileDetails.size();
Expand Down
Loading
Loading