Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
bhackett1024 committed Sep 13, 2024
1 parent 7eed684 commit 8231e7c
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 24 deletions.
38 changes: 34 additions & 4 deletions packages/protocol/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SourceLocation } from "@replayio/protocol";
import { SourceLocation, TimeStampedPoint } from "@replayio/protocol";

Check failure on line 1 in packages/protocol/utils.ts

View workflow job for this annotation

GitHub Actions / Trunk Check

prettier

Incorrect formatting, autoformat by running 'trunk fmt'

type ErrorHandler = (error: Error) => void;

Expand Down Expand Up @@ -154,17 +154,47 @@ export function breakdownSupplementalId(id: string): { id: string, supplementalI
return { id: match[2], supplementalIndex };
}

/**
export function sameSupplementalIndex(idA: string, idB: string) {
return breakdownSupplementalId(idA).supplementalIndex == breakdownSupplementalId(idB).supplementalIndex;
}

const SupplementalNumericStringShift = 200;

export function transformSupplementalNumericString(v: string, supplementalIndex: number): string {
assert(BigInt(v) < BigInt(1) << BigInt(SupplementalNumericStringShift));
if (!supplementalIndex) {
return v;
}
return (BigInt(v) | (BigInt(1) << BigInt(SupplementalNumericStringShift))).toString();
}

/*
* Compare 2 integers encoded as numeric strings, because we want to avoid using BigInt (for now).
* This will only work correctly if both strings encode positive integers (without decimal places),
* using the same base (usually 10) and don't use "fancy stuff" like leading "+", "0" or scientific
* notation.
*/
function compareNumericIntegers(a: string, b: string) {
return a.length < b.length ? -1 : a.length > b.length ? 1 : a < b ? -1 : a > b ? 1 : 0;
}

// Compare execution points, which must be from the same recording.
export function compareExecutionPoints(transformedA: string, transformedB: string) {
const { id: a, supplementalIndex: indexA } = breakdownSupplementalId(transformedA);
const { id: b, supplementalIndex: indexB } = breakdownSupplementalId(transformedB);
assert(indexA == indexB);
return a.length < b.length ? -1 : a.length > b.length ? 1 : a < b ? -1 : a > b ? 1 : 0;
assert(indexA == indexB, `Points ${transformedA} and ${transformedB} are not comparable`);
return compareNumericIntegers(a, b);
}

// Compare execution points along with their times. Falls back onto time
// comparison for points from different recordings.
export function compareTimeStampedPoints(transformedA: TimeStampedPoint, transformedB: TimeStampedPoint) {
const { id: a, supplementalIndex: indexA } = breakdownSupplementalId(transformedA.point);
const { id: b, supplementalIndex: indexB } = breakdownSupplementalId(transformedB.point);
if (indexA == indexB) {
return compareNumericIntegers(a, b);
}
return transformedA.time - transformedB.time;
}

export function locationsInclude(haystack: SourceLocation[], needle: SourceLocation) {
Expand Down
13 changes: 8 additions & 5 deletions packages/replay-next/components/console/MessagesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import { useMostRecentLoadedPause } from "replay-next/src/hooks/useMostRecentLoa
import { useStreamingMessages } from "replay-next/src/hooks/useStreamingMessages";
import {
getLoggableExecutionPoint,
getLoggableTime,
isEventLog,
isPointInstance,
isProtocolMessage,
isTerminalExpression,
isUncaughtException,
} from "replay-next/src/utils/loggables";
import { isExecutionPointsLessThan } from "replay-next/src/utils/time";

import { ConsoleSearchContext } from "./ConsoleSearchContext";
import CurrentTimeIndicator from "./CurrentTimeIndicator";
Expand All @@ -34,6 +34,7 @@ import TerminalExpressionRenderer from "./renderers/TerminalExpressionRenderer";
import UncaughtExceptionRenderer from "./renderers/UncaughtExceptionRenderer";
import styles from "./MessagesList.module.css";
import rendererStyles from "./renderers/shared.module.css";
import { compareTimeStampedPoints } from "protocol/utils";

type CurrentTimeIndicatorPlacement = Loggable | "begin" | "end";

Expand Down Expand Up @@ -66,21 +67,23 @@ function MessagesListSuspends({ forwardedRef }: { forwardedRef: ForwardedRef<HTM
} = useContext(ConsoleFiltersContext);
const { loggables, streamingStatus } = useContext(LoggablesContext);
const [searchState] = useContext(ConsoleSearchContext);
const { point: currentExecutionPoint } = useMostRecentLoadedPause() ?? {};
const { point: currentExecutionPoint, time: currentTime } = useMostRecentLoadedPause() ?? {};

// The Console should render a line indicating the current execution point.
// This point might match multiple logs– or it might be between logs, or after the last log, etc.
// This looking finds the best place to render the indicator.
const currentTimeIndicatorPlacement = useMemo<CurrentTimeIndicatorPlacement | null>(() => {
if (!currentExecutionPoint) {
if (!currentExecutionPoint || !currentTime) {
return null;
}
if (currentExecutionPoint === "0") {
return "begin";
}
const nearestLoggable = loggables.find(loggable => {
const executionPoint = getLoggableExecutionPoint(loggable);
if (!isExecutionPointsLessThan(executionPoint, currentExecutionPoint)) {
const point = getLoggableExecutionPoint(loggable);
const time = getLoggableTime(loggable);
const v = compareTimeStampedPoints({ point, time }, { point: currentExecutionPoint, time: currentTime });
if (v >= 0) {
return true;
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
useTransition,
} from "react";

import { assert } from "protocol/utils";
import { assert, sameSupplementalIndex } from "protocol/utils";
import AvatarImage from "replay-next/components/AvatarImage";
import { InlineErrorBoundary } from "replay-next/components/errors/InlineErrorBoundary";
import Icon from "replay-next/components/Icon";
Expand Down Expand Up @@ -214,6 +214,9 @@ export function PointPanelWithHitPoints({
if (!currentExecutionPoint) {
return null;
}
if (!sameSupplementalIndex(currentExecutionPoint, location.sourceId)) {
return null;
}
const executionPoints = hitPoints.map(hitPoint => hitPoint.point);
const index = findIndexBigInt(executionPoints, currentExecutionPoint, false);
return hitPoints[index] || null;
Expand Down
6 changes: 5 additions & 1 deletion packages/replay-next/src/suspense/FocusIntervalCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "suspense";

import { ProtocolError, isCommandError } from "shared/utils/error";
import { breakdownSupplementalId, transformSupplementalNumericString } from "protocol/utils";

type Options<Point extends number | bigint, Params extends Array<any>, Value> = {
debugLabel?: string;
Expand Down Expand Up @@ -35,7 +36,10 @@ export function createFocusIntervalCacheForExecutionPoints<Params extends Array<
return createFocusIntervalCache<bigint, Params, Value>({
...rest,
getPointForValue: (value: Value): bigint => {
return BigInt(getPointForValue(value));
const transformedPoint = getPointForValue(value);
const { id: point, supplementalIndex } = breakdownSupplementalId(transformedPoint);
const newPoint = transformSupplementalNumericString(point, supplementalIndex);
return BigInt(newPoint);
},
load: (start: bigint, end: bigint, ...params: [...Params, IntervalCacheLoadOptions<Value>]) =>
load(start.toString(), end.toString(), ...params),
Expand Down
28 changes: 20 additions & 8 deletions packages/replay-next/src/suspense/HitPointsCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createCache } from "suspense";

import { breakpointPositionsIntervalCache } from "replay-next/src/suspense/BreakpointPositionsCache";
import { bucketBreakpointLines } from "replay-next/src/utils/source";
import { compareExecutionPoints } from "protocol/utils";
import { compareExecutionPoints, breakdownSupplementalId } from "protocol/utils";
import { MAX_POINTS_TO_RUN_EVALUATION } from "shared/client/ReplayClient";
import {
HitPointStatus,
Expand Down Expand Up @@ -107,13 +107,25 @@ export const hitPointsForLocationCache = createCache<
let hitPoints: TimeStampedPoint[] = [];
let status: HitPointStatus = "complete";
try {
hitPoints = await hitPointsCache.readAsync(
BigInt(range.begin),
BigInt(range.end),
replayClient,
location,
condition
);
const { id: sourceId, supplementalIndex } = breakdownSupplementalId(location.sourceId);
if (supplementalIndex) {
if (condition) {
throw new Error("NYI");
}
const sources = await sourcesByIdCache.readAsync(replayClient);
const locations = getCorrespondingLocations(sources, location);
hitPoints = await replayClient.findPoints(
{ kind: "locations", locations }, undefined
);
} else {
hitPoints = await hitPointsCache.readAsync(
BigInt(range.begin),
BigInt(range.end),
replayClient,
location,
condition
);
}
if (hitPoints.length > MAX_POINTS_TO_RUN_EVALUATION) {
status = "too-many-points-to-run-analysis";
}
Expand Down
7 changes: 5 additions & 2 deletions packages/replay-next/src/utils/loggables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TerminalExpression } from "replay-next/src/contexts/TerminalContext";
import { EventLog } from "replay-next/src/suspense/EventsCache";
import { UncaughtException } from "replay-next/src/suspense/ExceptionsCache";

import { compareExecutionPoints } from "./time";
import { compareTimeStampedPoints } from "protocol/utils";

export function isEventLog(loggable: Loggable): loggable is EventLog {
return loggable.type === "EventLog";
Expand Down Expand Up @@ -80,5 +80,8 @@ export function loggableSort(a: Loggable, b: Loggable): number {
}
}

return compareExecutionPoints(aPoint, bPoint);
const aTime = getLoggableTime(a);
const bTime = getLoggableTime(b);

return compareTimeStampedPoints({ point: aPoint, time: aTime }, { point: bPoint, time: bTime });
}
5 changes: 2 additions & 3 deletions packages/replay-next/src/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import differenceInWeeks from "date-fns/differenceInWeeks";
import differenceInYears from "date-fns/differenceInYears";
import padStart from "lodash/padStart";
import prettyMilliseconds from "pretty-ms";
import { compareExecutionPoints as baseCompareExecutionPoints } from "protocol/utils";

export function compareExecutionPoints(a: ExecutionPoint, b: ExecutionPoint): number {
return Number(BigInt(a) - BigInt(b));
}
export const compareExecutionPoints = baseCompareExecutionPoints;

export function isExecutionPointsGreaterThan(a: ExecutionPoint, b: ExecutionPoint): boolean {
return compareExecutionPoints(a, b) > 0;
Expand Down

0 comments on commit 8231e7c

Please sign in to comment.