-
Notifications
You must be signed in to change notification settings - Fork 535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add optional dispose flag for forks after transaction #23298
Conversation
@@ -482,6 +483,9 @@ export type SharedTreeOptions = Partial<ICodecOptions> & | |||
Partial<SharedTreeFormatOptions> & | |||
ForestOptions; | |||
|
|||
export interface SharedTreeOptionsSpecial extends SharedTreeOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "SharedTreeOptionsInternal"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to suggested name
@@ -393,6 +395,7 @@ export class TreeCheckout implements ITreeCheckoutFork { | |||
/** Optional logger for telemetry. */ | |||
private readonly logger?: ITelemetryLoggerExt, | |||
private readonly breaker: Breakable = new Breakable("TreeCheckout"), | |||
private readonly disposeForksAfterTransaction?: boolean, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private readonly disposeForksAfterTransaction?: boolean, | |
private readonly disposeForksAfterTransaction = false, |
If you default on initialization, then it will be a boolean
rather than a boolean | undefined
, and any code in the class that reads it doesn't need to worry about handling undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated to default on initialization
|
||
forks.forEach((fork) => fork.dispose()); | ||
if (this.disposeForksAfterTransaction !== false) { | ||
forks.forEach((fork) => fork.dispose()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're not doing this disposal, you shouldn't need any of the fork tracking code above either. The only reason we subscribe to the fork event is to do this disposal. If disposeForksAfterTransaction is false, then probably just have forks
be undefined or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated to only track forks when dispose flag is true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is still some code running that doesn't need to. How about this: move all of the code related to the forking stuff into a nice, encapulated helper function. Something like:
// Keeps track of all new forks created until the returned function is invoked, which will dispose all of those forks
// The returned function may only be called once
function trackForksForDisposal(checkout: TreeCheckout): () => void {
const forks = new Set<TreeCheckout>();
let onForkUnSubscribe: () => void | undefined;
const onDisposeUnSubscribes: (() => void)[] = [];
onForkUnSubscribe = onForkTransitive(checkout, (fork) => {
forks.add(fork);
onDisposeUnSubscribes.push(fork.events.on("dispose", () => forks.delete(fork)));
});
let disposed = false;
return () => {
assert(!disposed, "Forks may only be disposed once");
forks.forEach((fork) => fork.dispose());
onDisposeUnSubscribes.forEach((unsubscribe) => unsubscribe());
onForkUnSubscribe();
disposed = true;
}
}
Then you can just do:
const disposeForks = this.disposeForksAfterTransaction ? collectForksForDisposal(this) : undefined;
// ...
disposeForks?.();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, it does not seem to populate the forks properly when combining everything into one function. I have created 2 helper functions to simplify it a bit though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh. Why? It should be a pretty straightforward code move 🤔
The way it is now is more complicated and verbose than either the original state or the above suggestion, IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My mistake! Turns out I was calling trackForksForDisposal
in the wrong place (within the return of the constructor). It seems to be working properly :)
|
||
forks.forEach((fork) => fork.dispose()); | ||
if (this.disposeForksAfterTransaction !== false) { | ||
forks.forEach((fork) => fork.dispose()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is still some code running that doesn't need to. How about this: move all of the code related to the forking stuff into a nice, encapulated helper function. Something like:
// Keeps track of all new forks created until the returned function is invoked, which will dispose all of those forks
// The returned function may only be called once
function trackForksForDisposal(checkout: TreeCheckout): () => void {
const forks = new Set<TreeCheckout>();
let onForkUnSubscribe: () => void | undefined;
const onDisposeUnSubscribes: (() => void)[] = [];
onForkUnSubscribe = onForkTransitive(checkout, (fork) => {
forks.add(fork);
onDisposeUnSubscribes.push(fork.events.on("dispose", () => forks.delete(fork)));
});
let disposed = false;
return () => {
assert(!disposed, "Forks may only be disposed once");
forks.forEach((fork) => fork.dispose());
onDisposeUnSubscribes.forEach((unsubscribe) => unsubscribe());
onForkUnSubscribe();
disposed = true;
}
}
Then you can just do:
const disposeForks = this.disposeForksAfterTransaction ? collectForksForDisposal(this) : undefined;
// ...
disposeForks?.();
packages/dds/tree/src/test/utils.ts
Outdated
) { | ||
super({ jsonValidator: typeboxValidator }); | ||
super(options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this better?
super(options); | |
super({ ...options, jsonValidator: typeboxValidator }); |
You want this to use typeboxValidator
no matter what, correct? Otherwise it's broken? Or, is there a legitimate use case for a subclass of this which allows a different validator?
And if so, you'd still want to supply typeboxValidator
if the subclass didn't supply anything. So that'd at least be:
super({ ...options, jsonValidator: options.jsonValidator ?? typeboxValidator })
In either case, you can change the default value for the options
parameter to be {}
, and you should follow the same pattern in the other constructor of your new subclass (because it could be subclassed).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated with suggestion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
@@ -913,3 +909,22 @@ export class TreeCheckout implements ITreeCheckoutFork { | |||
); | |||
} | |||
} | |||
|
|||
// Keeps track of all new forks created until the returned function is invoked, which will dispose all of those forks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: one of the benefits of factoring code out into helper functions is that you can put doc-comments on them. So let's take advantage of that and make this a full-on doc comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added doc comment to helper function
Description
This PR adds a flag to not dispose of the fork after the transaction is commited/aborted.