Skip to content

Commit

Permalink
Improve performance via Triemap in workspace (#1406)
Browse files Browse the repository at this point in the history
  • Loading branch information
pderaaij authored Oct 15, 2024
1 parent d7c92f8 commit 5a6ef64
Show file tree
Hide file tree
Showing 5 changed files with 1,809 additions and 1,825 deletions.
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

0 comments on commit 5a6ef64

Please sign in to comment.