Skip to content

Commit a942588

Browse files
committed
fs: remove "NodeSelector", add checks to memoryfs, passed simple test
1 parent d5798d2 commit a942588

File tree

4 files changed

+78
-94
lines changed

4 files changed

+78
-94
lines changed

src/backend/src/filesystem/node/selectors.js

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,8 @@
1919
const _path = require('path');
2020
const { PuterPath } = require('../lib/PuterPath');
2121

22-
class NodeSelector {
23-
path = null;
24-
uid = null;
25-
}
26-
27-
class NodePathSelector extends NodeSelector {
22+
class NodePathSelector {
2823
constructor (path) {
29-
super();
3024
this.value = path;
3125
}
3226

@@ -40,9 +34,8 @@ class NodePathSelector extends NodeSelector {
4034
}
4135
}
4236

43-
class NodeUIDSelector extends NodeSelector {
37+
class NodeUIDSelector {
4438
constructor (uid) {
45-
super();
4639
this.value = uid;
4740
}
4841

@@ -65,9 +58,8 @@ class NodeUIDSelector extends NodeSelector {
6558
}
6659
}
6760

68-
class NodeInternalIDSelector extends NodeSelector {
61+
class NodeInternalIDSelector {
6962
constructor (service, id, debugInfo) {
70-
super();
7163
this.service = service;
7264
this.id = id;
7365
this.debugInfo = debugInfo;
@@ -89,9 +81,8 @@ class NodeInternalIDSelector extends NodeSelector {
8981
}
9082
}
9183

92-
class NodeChildSelector extends NodeSelector {
84+
class NodeChildSelector {
9385
constructor (parent, name) {
94-
super();
9586
this.parent = parent;
9687
this.name = name;
9788
}
@@ -110,7 +101,7 @@ class NodeChildSelector extends NodeSelector {
110101
}
111102
}
112103

113-
class RootNodeSelector extends NodeSelector {
104+
class RootNodeSelector {
114105
static entry = {
115106
is_dir: true,
116107
is_root: true,
@@ -123,7 +114,6 @@ class RootNodeSelector extends NodeSelector {
123114
node.uid = PuterPath.NULL_UUID;
124115
}
125116
constructor () {
126-
super();
127117
this.entry = this.constructor.entry;
128118
}
129119

@@ -132,9 +122,8 @@ class RootNodeSelector extends NodeSelector {
132122
}
133123
}
134124

135-
class NodeRawEntrySelector extends NodeSelector {
125+
class NodeRawEntrySelector {
136126
constructor (entry) {
137-
super();
138127
// Fix entries from get_descendants
139128
if ( ! entry.uuid && entry.uid ) {
140129
entry.uuid = entry.uid;
@@ -165,7 +154,7 @@ class NodeRawEntrySelector extends NodeSelector {
165154
* - path
166155
* - uid
167156
*
168-
* @param {NodeSelector} selector
157+
* @param {NodePathSelector | NodeUIDSelector | NodeChildSelector | RootNodeSelector | NodeRawEntrySelector} selector
169158
*/
170159
function try_infer_attributes (selector) {
171160
if ( selector instanceof NodePathSelector ) {
@@ -201,7 +190,6 @@ const relativeSelector = (parent, path) => {
201190
}
202191

203192
module.exports = {
204-
NodeSelector,
205193
NodePathSelector,
206194
NodeUIDSelector,
207195
NodeInternalIDSelector,

src/backend/src/modules/puterfs/MountpointService.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,6 @@ class MountpointService extends BaseService {
8888
}
8989

9090
async get_provider (selector) {
91-
// type check
92-
if ( ! (selector instanceof NodeSelector) ) {
93-
throw new Error('Invalid selector type');
94-
}
95-
9691
try_infer_attributes(selector);
9792

9893
if ( selector instanceof RootNodeSelector ) {

src/backend/src/modules/puterfs/customfs/MemoryFSProvider.js

Lines changed: 68 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ const { Context } = require('../../../util/context');
2323
const { v4: uuidv4 } = require('uuid');
2424
const config = require('../../../config');
2525
const {
26-
try_infer_attributes,
2726
NodeChildSelector,
2827
NodePathSelector,
2928
NodeUIDSelector,
30-
NodeSelector,
29+
NodeRawEntrySelector,
30+
RootNodeSelector,
31+
try_infer_attributes,
3132
} = require('../../../filesystem/node/selectors');
3233
const fsCapabilities = require('../../../filesystem/definitions/capabilities');
3334
const APIError = require('../../../api/APIError');
@@ -198,46 +199,22 @@ class MemoryFSProvider {
198199
* Check if a given node exists.
199200
*
200201
* @param {Object} param
201-
* @param {NodeSelector} param.selector - The selector used for checking.
202+
* @param {NodePathSelector | NodeUIDSelector | NodeChildSelector | RootNodeSelector | NodeRawEntrySelector} param.selector - The selector used for checking.
202203
* @returns {Promise<boolean>} - True if the node exists, false otherwise.
203204
*/
204205
async quick_check({ selector }) {
205-
// memoryfs relies on attributes path/uid
206-
try_infer_attributes(selector);
207-
208-
// shortcut: has full path
209-
if (selector?.path) {
210-
const inner_path = this._inner_path(selector.path);
206+
if (selector instanceof NodePathSelector) {
207+
const inner_path = this._inner_path(selector.value);
211208
return this.entriesByPath.has(inner_path);
212209
}
213210

214-
// shortcut: has uid
215-
if (selector?.uid) {
216-
return this.entriesByUUID.has(selector.uid);
211+
if (selector instanceof NodeUIDSelector) {
212+
return this.entriesByUUID.has(selector.value);
217213
}
218214

219-
if (selector instanceof NodeChildSelector) {
220-
let parent_entry = null;
221-
if (selector.parent instanceof NodeUIDSelector) {
222-
// shortcut: uid parent + name child
223-
parent_entry = this.entriesByUUID.get(selector.parent.uid);
224-
} else {
225-
// composite parent, has to stat it first
226-
parent_entry = await this.stat({
227-
selector: selector.parent,
228-
});
229-
}
230-
231-
if (parent_entry) {
232-
const full_path = _path.join(parent_entry.path, selector.name);
233-
const path_selector = new NodePathSelector(full_path);
234-
return this.quick_check({
235-
selector: path_selector,
236-
});
237-
}
238-
}
239-
240-
return false;
215+
// fallback to stat
216+
const entry = await this.stat({ selector });
217+
return !!entry;
241218
}
242219

243220
/**
@@ -247,42 +224,47 @@ class MemoryFSProvider {
247224
* `path` of the absolute path from the root.
248225
*
249226
* @param {Object} param
250-
* @param {NodeSelector} param.selector - The selector to stat.
227+
* @param {NodePathSelector | NodeUIDSelector | NodeChildSelector | RootNodeSelector | NodeRawEntrySelector} param.selector - The selector to stat.
251228
* @returns {Promise<MemoryFile|null>} - The result of the stat operation, or `null` if the node doesn't exist.
252229
*/
253230
async stat({ selector }) {
254-
// memoryfs relies on attributes path/uid
255231
try_infer_attributes(selector);
256232

257233
let entry_uuid = null;
258234

259-
if (selector?.path) {
235+
if (selector instanceof NodePathSelector) {
260236
// stat by path
261-
const inner_path = this._inner_path(selector.path);
237+
const inner_path = this._inner_path(selector.value);
262238
entry_uuid = this.entriesByPath.get(inner_path);
263-
} else if (selector?.uid) {
239+
} else if (selector instanceof NodeUIDSelector) {
264240
// stat by uid
265-
entry_uuid = selector.uid;
266-
} else {
267-
// the tricky case: selector has a composite (i.e. non path/uid) parent
268-
if (selector instanceof NodeChildSelector) {
241+
entry_uuid = selector.value;
242+
} else if (selector instanceof NodeChildSelector) {
243+
if (selector.path) {
244+
// Shouldn't care about about parent when the "path" is present
245+
// since it might have different provider.
246+
return await this.stat({
247+
selector: new NodePathSelector(selector.path),
248+
});
249+
} else {
250+
// recursively stat the parent and then stat the child
269251
const parent_entry = await this.stat({
270252
selector: selector.parent,
271253
});
272254
if (parent_entry) {
273255
const full_path = _path.join(parent_entry.path, selector.name);
274-
const path_selector = new NodePathSelector(full_path);
275256
return await this.stat({
276-
selector: path_selector,
257+
selector: new NodePathSelector(full_path),
277258
});
278259
}
279260
}
280-
261+
} else {
262+
// other selectors shouldn't reach here, i.e., it's an internal logic error
281263
throw APIError.create('invalid_node');
282264
}
283265

284266
const entry = this.entriesByUUID.get(entry_uuid);
285-
if ( ! entry ) {
267+
if (!entry) {
286268
return null;
287269
}
288270

@@ -304,7 +286,7 @@ class MemoryFSProvider {
304286
async readdir({ context, node }) {
305287
// prerequistes: get required path via stat
306288
const entry = await this.stat({ selector: node.selector });
307-
if ( ! entry ) {
289+
if (!entry) {
308290
throw APIError.create('invalid_node');
309291
}
310292

@@ -338,21 +320,28 @@ class MemoryFSProvider {
338320
async mkdir({ context, parent, name }) {
339321
// prerequistes: get required path via stat
340322
const parent_entry = await this.stat({ selector: parent.selector });
341-
if ( ! parent_entry ) {
323+
if (!parent_entry) {
342324
throw APIError.create('invalid_node');
343325
}
344326

345327
const full_path = _path.join(parent_entry.path, name);
346328
const inner_path = this._inner_path(full_path);
347329

348-
const entry = new MemoryFile({
349-
path: inner_path,
350-
is_dir: true,
351-
content: null,
352-
parent_uid: parent_entry.uuid,
353-
});
354-
this.entriesByPath.set(inner_path, entry.uuid);
355-
this.entriesByUUID.set(entry.uuid, entry);
330+
let entry = null;
331+
if (this.entriesByPath.has(inner_path)) {
332+
throw APIError.create('item_with_same_name_exists', null, {
333+
entry_name: full_path,
334+
});
335+
} else {
336+
entry = new MemoryFile({
337+
path: inner_path,
338+
is_dir: true,
339+
content: null,
340+
parent_uid: parent_entry.uuid,
341+
});
342+
this.entriesByPath.set(inner_path, entry.uuid);
343+
this.entriesByUUID.set(entry.uuid, entry);
344+
}
356345

357346
// create the node
358347
const fs = context.get('services').get('filesystem');
@@ -374,9 +363,11 @@ class MemoryFSProvider {
374363
* @returns {Promise<void>}
375364
*/
376365
async rmdir({ context, node, options = {} }) {
366+
this._integrity_check();
367+
377368
// prerequistes: get required path via stat
378369
const entry = await this.stat({ selector: node.selector });
379-
if ( ! entry ) {
370+
if (!entry) {
380371
throw APIError.create('invalid_node');
381372
}
382373

@@ -424,7 +415,7 @@ class MemoryFSProvider {
424415
async unlink({ context, node }) {
425416
// prerequistes: get required path via stat
426417
const entry = await this.stat({ selector: node.selector });
427-
if ( ! entry ) {
418+
if (!entry) {
428419
throw APIError.create('invalid_node');
429420
}
430421

@@ -447,7 +438,7 @@ class MemoryFSProvider {
447438
async move({ context, node, new_parent, new_name, metadata }) {
448439
// prerequistes: get required path via stat
449440
const new_parent_entry = await this.stat({ selector: new_parent.selector });
450-
if ( ! new_parent_entry ) {
441+
if (!new_parent_entry) {
451442
throw APIError.create('invalid_node');
452443
}
453444

@@ -534,20 +525,27 @@ class MemoryFSProvider {
534525
async write_new({ context, parent, name, file }) {
535526
// prerequistes: get required path via stat
536527
const parent_entry = await this.stat({ selector: parent.selector });
537-
if ( ! parent_entry ) {
528+
if (!parent_entry) {
538529
throw APIError.create('invalid_node');
539530
}
540531
const full_path = _path.join(parent_entry.path, name);
541532
const inner_path = this._inner_path(full_path);
542533

543-
const entry = new MemoryFile({
544-
path: inner_path,
545-
is_dir: false,
546-
content: file.stream.read(),
547-
parent_uid: parent_entry.uuid,
548-
});
549-
this.entriesByPath.set(inner_path, entry.uuid);
550-
this.entriesByUUID.set(entry.uuid, entry);
534+
let entry = null;
535+
if (this.entriesByPath.has(inner_path)) {
536+
throw APIError.create('item_with_same_name_exists', null, {
537+
entry_name: full_path,
538+
});
539+
} else {
540+
entry = new MemoryFile({
541+
path: inner_path,
542+
is_dir: false,
543+
content: file.stream.read(),
544+
parent_uid: parent_entry.uuid,
545+
});
546+
this.entriesByPath.set(inner_path, entry.uuid);
547+
this.entriesByUUID.set(entry.uuid, entry);
548+
}
551549

552550
const fs = context.get('services').get('filesystem');
553551
const node = await fs.node(entry.uuid);
@@ -570,7 +568,7 @@ class MemoryFSProvider {
570568
*/
571569
async write_overwrite({ context, node, file }) {
572570
const entry = await this.stat({ selector: node.selector });
573-
if ( ! entry ) {
571+
if (!entry) {
574572
throw APIError.create('invalid_node');
575573
}
576574
const inner_path = this._inner_path(entry.path);

tools/api-tester/apitest.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ async function test({ mountpoint }) {
129129
config: conf,
130130
}));
131131

132+
// TODO: merge it into the entry point
133+
require('./benches/simple.js')(registry);
134+
132135
require('./tests/__entry__.js')(registry);
133136
require('./benches/__entry__.js')(registry);
134137

0 commit comments

Comments
 (0)