Skip to content
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

Improve performance via Triemap in workspace #1406

Merged
merged 3 commits into from
Oct 15, 2024
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
16 changes: 15 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/foam-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@
"lodash": "^4.17.21",
"lru-cache": "^7.14.1",
"markdown-it-regex": "^0.2.0",
"mnemonist": "^0.39.8",
"path-browserify": "^1.0.1",
"remark-frontmatter": "^2.0.0",
"remark-parse": "^8.0.2",
Expand Down
63 changes: 49 additions & 14 deletions packages/foam-vscode/src/core/model/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Emitter } from '../common/event';
import { ResourceProvider } from './provider';
import { IDisposable } from '../common/lifecycle';
import { IDataStore } from '../services/datastore';
import TrieMap from 'mnemonist/trie-map';

export class FoamWorkspace implements IDisposable {
private onDidAddEmitter = new Emitter<Resource>();
Expand All @@ -20,7 +21,7 @@ export class FoamWorkspace implements IDisposable {
/**
* Resources by path
*/
private _resources: Map<string, Resource> = new Map();
private _resources: TrieMap<string, Resource> = new TrieMap();

/**
* @param defaultExtension: The default extension for notes in this workspace (e.g. `.md`)
Expand All @@ -33,16 +34,19 @@ export class FoamWorkspace implements IDisposable {

set(resource: Resource) {
const old = this.find(resource.uri);
this._resources.set(normalize(resource.uri.path), resource);

// store resource
this._resources.set(this.getTrieIdentifier(resource.uri.path), resource);

isSome(old)
? this.onDidUpdateEmitter.fire({ old: old, new: resource })
: this.onDidAddEmitter.fire(resource);
return this;
}

delete(uri: URI) {
const deleted = this._resources.get(normalize(uri.path));
this._resources.delete(normalize(uri.path));
const deleted = this._resources.get(this.getTrieIdentifier(uri));
this._resources.delete(this.getTrieIdentifier(uri));

isSome(deleted) && this.onDidDeleteEmitter.fire(deleted);
return deleted ?? null;
Expand All @@ -57,7 +61,11 @@ export class FoamWorkspace implements IDisposable {
}

public resources(): IterableIterator<Resource> {
return this._resources.values();
const resources: Array<Resource> = Array.from(
this._resources.values()
).sort(Resource.sortByPath);

return resources.values();
}

public get(uri: URI): Resource {
Expand All @@ -70,17 +78,21 @@ export class FoamWorkspace implements IDisposable {
}

public listByIdentifier(identifier: string): Resource[] {
const needle = normalize('/' + identifier);
let needle = this.getTrieIdentifier(identifier);

const mdNeedle =
getExtension(needle) !== this.defaultExtension
? needle + this.defaultExtension
getExtension(normalize(identifier)) !== this.defaultExtension
? this.getTrieIdentifier(identifier + this.defaultExtension)
: undefined;

const resources: Resource[] = [];
for (const key of this._resources.keys()) {
if (key.endsWith(mdNeedle) || key.endsWith(needle)) {
resources.push(this._resources.get(normalize(key)));
}

this._resources.find(needle).forEach(elm => resources.push(elm[1]));

if (mdNeedle) {
this._resources.find(mdNeedle).forEach(elm => resources.push(elm[1]));
}

return resources.sort(Resource.sortByPath);
}

Expand Down Expand Up @@ -119,9 +131,32 @@ export class FoamWorkspace implements IDisposable {
return identifier;
}

/**
* Returns a note identifier in reversed order. Used to optimise the storage of notes in
* the workspace to optimise retrieval of notes.
*
* @param reference the URI path to reverse
*/
private getTrieIdentifier(reference: URI | string): string {
let path: string;
if (reference instanceof URI) {
path = (reference as URI).path;
} else {
path = reference as string;
}

let reversedPath = normalize(path).split('/').reverse().join('/');

if (reversedPath.indexOf('/') < 0) {
reversedPath = reversedPath + '/';
}

return reversedPath;
}

public find(reference: URI | string, baseUri?: URI): Resource | null {
if (reference instanceof URI) {
return this._resources.get(normalize((reference as URI).path)) ?? null;
return this._resources.get(this.getTrieIdentifier(reference)) ?? null;
}
let resource: Resource | null = null;
const [path, fragment] = (reference as string).split('#');
Expand All @@ -135,7 +170,7 @@ export class FoamWorkspace implements IDisposable {
: isSome(baseUri)
? baseUri.resolve(candidate).path
: null;
resource = this._resources.get(normalize(searchKey));
resource = this._resources.get(this.getTrieIdentifier(searchKey));
if (resource) {
break;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/foam-vscode/src/features/navigation-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ describe('Document navigation', () => {
doc,
new vscode.Position(0, 26)
);

// Make sure the references are sorted by position, so we match the right expectation
refs.sort((a, b) => a.range.start.character - b.range.start.character);

expect(refs.length).toEqual(2);
expect(refs[0]).toEqual({
uri: toVsCodeUri(fileB.uri),
Expand Down
Loading
Loading