perf: [+] readdirstat_uuid optimized implementation

This commit is contained in:
KernelDeimos
2025-12-15 16:54:20 -05:00
parent 6d36c90032
commit 11ef175560
6 changed files with 87 additions and 2 deletions

View File

@@ -73,6 +73,7 @@ const {
NodeChildSelector,
NodeUIDSelector,
NodeInternalIDSelector,
NodeRawEntrySelector,
} = extension.import('core').fs.selectors;
const {
@@ -112,6 +113,7 @@ export default class PuterFSProvider {
capabilities.UUID,
capabilities.OPERATION_TRACE,
capabilities.READDIR_UUID_MODE,
capabilities.READDIRSTAT_UUID,
capabilities.PUTER_SHORTCUT,
capabilities.COPY_TREE,
@@ -206,6 +208,29 @@ export default class PuterFSProvider {
}
// #endregion
// #region Optimization
/**
* The readdirstat_uuid operation is only available for filesystem
* immplementations with READDIR_UUID_MODE enabled. This implements
* an optimized readdir operation when the UUID is already known.
* @param {*} param0
*/
async readdirstat_uuid ({
uuid,
options = {},
}) {
const entries = await this.fsEntryController.get_descendants_full(uuid, options);
const nodes = Promise.all(Array.prototype.map.call(entries, raw_entry => {
const node = svc_fs.node(new NodeRawEntrySelector(raw_entry, {
found_thumbnail: options.thumbnail,
}));
node.found = true; // TODO: how is it possible for this to be false?
return node;
}));
return nodes;
};
// #endregion
// #region Standard FS
/**
@@ -374,6 +399,11 @@ export default class PuterFSProvider {
let entry;
// stat doesn't work with RawEntrySelector
if ( selector instanceof NodeRawEntrySelector ) {
selector = new NodeUIDSelector(node.uid);
}
await new Promise (rslv => {
const detachables = new MultiDetachable();

View File

@@ -208,6 +208,12 @@ export default class {
return answer.entry;
}
/**
* Returns UUIDs of child fsentries under the specified
* parent fsentry
* @param {string} uuid - UUID of parent fsentry
* @returns fsentry[]
*/
async get_descendants (uuid) {
return uuid === PuterPath.NULL_UUID
? await db.read('SELECT uuid FROM fsentries WHERE parent_uid IS NULL',
@@ -217,6 +223,25 @@ export default class {
;
}
/**
* Returns full fsentry nodes for entries under the specified
* parent fsentry
* @param {string} uuid - UUID of parent fsentry
* @returns fsentry[]
*/
async get_descendants_full (uuid, fetch_entry_options) {
const { thumbnail } = fetch_entry_options;
const columns = `${
this.defaultProperties.join(', ')
}${thumbnail ? ', thumbnail' : ''}`;
return uuid === PuterPath.NULL_UUID
? await db.read(`SELECT ${columns} FROM fsentries WHERE parent_uid IS NULL`,
[uuid])
: await db.read(`SELECT ${columns} FROM fsentries WHERE parent_uid = ?`,
[uuid])
;
}
async get_recursive_size (uuid) {
const cte_query = `
WITH RECURSIVE descendant_cte AS (

View File

@@ -84,7 +84,7 @@ module.exports = class FSNodeContext {
}) {
const ecmap = Context.get(ECMAP.SYMBOL);
if ( ecmap ) {
if ( ecmap && !(selector instanceof NodeRawEntrySelector) ) {
// We might return an existing FSNodeContext
const maybe_node = ecmap
?.get_fsNodeContext_from_selector?.(selector);

View File

@@ -37,6 +37,7 @@ const capabilityNames = [
'move-tree',
'remove-tree',
'get-recursive-size',
'readdirstat_uuid',
// Behavior Capabilities
'case-sensitive',

View File

@@ -73,6 +73,27 @@ class LLReadDir extends LLFilesystemOperation {
const capabilities = subject.provider.get_capabilities();
// UUID Mode
optimization: {
const uuid_selector = subject.get_selector_of_type(NodeUIDSelector);
// Skip this optimization if there is no UUID
if ( ! uuid_selector ) {
break optimization;
}
// Skip this optimization if the filesystem doesn't implement
// the "readdirstat_uuid" macro operation.
if ( ! capabilities.has(fsCapabilities.READDIRSTAT_UUID) ) {
break optimization;
}
const uuid = uuid_selector.value;
return await subject.provider.readdirstat_uuid({
uuid,
options: { thumbnail: true },
});
}
if ( capabilities.has(fsCapabilities.READDIR_UUID_MODE) ) {
this.checkpoint('readdir uuid mode');
const child_uuids = await subject.provider.readdir({

View File

@@ -141,8 +141,13 @@ class RootNodeSelector extends NodeSelector {
}
class NodeRawEntrySelector extends NodeSelector {
constructor (entry) {
constructor (entry, details_about_fetch = {}) {
super();
// The `details_about_fetch` object lets us simulate non-entry state
// that occurs after a node has been fetched
this.details_about_fetch = details_about_fetch;
// Fix entries from get_descendants
if ( !entry.uuid && entry.uid ) {
entry.uuid = entry.uid;
@@ -156,6 +161,9 @@ class NodeRawEntrySelector extends NodeSelector {
}
setPropertiesKnownBySelector (node) {
if ( this.details_about_fetch.found_thumbnail ) {
node.found_thumbnail = true;
}
node.found = true;
node.entry = this.entry;
node.uid = this.entry.uid ?? this.entry.uuid;