mirror of
https://github.com/HeyPuter/puter.git
synced 2025-12-21 12:59:52 -06:00
perf: [+] readdirstat_uuid optimized implementation
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -37,6 +37,7 @@ const capabilityNames = [
|
||||
'move-tree',
|
||||
'remove-tree',
|
||||
'get-recursive-size',
|
||||
'readdirstat_uuid',
|
||||
|
||||
// Behavior Capabilities
|
||||
'case-sensitive',
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user