Skip to content

Commit

Permalink
Rejects stale snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Nov 30, 2021
1 parent 15ae6d0 commit 3c07f62
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/core/Decorations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ export default class Decorations {
this.constructDecorations(this.graph.fontMeasurements);
}

/**
* Register to be notified when decoration styles are updated, for example if
* the user enables a new hat style
* @param listener A function to be called when decoration styles are updated
* @returns A function that can be called to unsubscribe from notifications
*/
registerDecorationChangeListener(listener: DecorationChangeListener) {
this.decorationChangeListeners.push(listener);

Expand Down
35 changes: 35 additions & 0 deletions src/core/HatTokenMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,31 @@ import { HatStyleName } from "./constants";
import { Graph } from "../typings/Types";
import { IndividualHatMap, ReadOnlyHatMap } from "./IndividualHatMap";
import { HatAllocator } from "./HatAllocator";
import { hrtime } from "process";
import { abs } from "../util/bigint";

/**
* Maximum age for the pre-phrase snapshot before we consider it to be stale
*/
const PRE_PHRASE_SNAPSHOT_MAX_AGE_NS = BigInt(6e10); // 60 seconds

/**
* Maps from (hatStyle, character) pairs to tokens
*/
export default class HatTokenMap {
/**
* This is the active map the changes every time we reallocate hats. It is
* liable to change in the middle of a phrase.
*/
private activeMap: IndividualHatMap;

/**
* This is a snapshot of the hat map that remains stable over the course of a
* phrase. Ranges will be updated to account for changes to the document, but a
* hat with the same color and shape will refer to the same logical range.
*/
private prePhraseMapSnapshot?: IndividualHatMap;
private prePhraseMapsSnapshotTimestamp: bigint | null = null;

private lastSignalVersion: string | null = null;
private hatAllocator: HatAllocator;
Expand Down Expand Up @@ -47,7 +65,10 @@ export default class HatTokenMap {
}

private async getActiveMap() {
// NB: We need to take a snapshot of the hat map before we make any
// modifications if it is the beginning of the phrase
await this.maybeTakePrePhraseSnapshot();

return this.activeMap;
}

Expand All @@ -61,6 +82,9 @@ export default class HatTokenMap {
* @returns A readable snapshot of the map
*/
async getReadableMap(usePrePhraseSnapshot: boolean): Promise<ReadOnlyHatMap> {
// NB: Take a snapshot before we return the map if it is the beginning of
// the phrase so all commands will get the same map over the course of the
// phrase
await this.maybeTakePrePhraseSnapshot();

if (usePrePhraseSnapshot) {
Expand All @@ -78,6 +102,16 @@ export default class HatTokenMap {
return this.activeMap;
}

if (
abs(hrtime.bigint() - this.prePhraseMapsSnapshotTimestamp!) >
PRE_PHRASE_SNAPSHOT_MAX_AGE_NS
) {
console.error(
"Navigation map pre-phrase snapshot requested, but snapshot is more than a minute old"
);
return this.activeMap;
}

return this.prePhraseMapSnapshot;
}

Expand Down Expand Up @@ -115,5 +149,6 @@ export default class HatTokenMap {
}

this.prePhraseMapSnapshot = this.activeMap.clone();
this.prePhraseMapsSnapshotTimestamp = hrtime.bigint();
}
}
3 changes: 3 additions & 0 deletions src/util/bigint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function abs(x: bigint) {
return x < BigInt(0) ? -x : x;
}

0 comments on commit 3c07f62

Please sign in to comment.