Skip to content

Commit 27c1e62

Browse files
XiaochenCuiKernelDeimos
authored andcommitted
fs: ll_write -> provider.write
1 parent 026a908 commit 27c1e62

File tree

6 files changed

+383
-212
lines changed

6 files changed

+383
-212
lines changed

src/backend/src/filesystem/ll_operations/ll_mkdir.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class LLMkdir extends LLFilesystemOperation {
3232

3333
async _run () {
3434
const { parent, name, immutable } = this.values;
35-
return parent.provider.mkdir({
35+
return await parent.provider.mkdir({
3636
context: this.context,
3737
parent,
3838
name,

src/backend/src/filesystem/ll_operations/ll_write.js

Lines changed: 37 additions & 209 deletions
Original file line numberDiff line numberDiff line change
@@ -145,100 +145,46 @@ class LLWriteBase extends LLFilesystemOperation {
145145
}
146146
}
147147

148+
/**
149+
* The "overwrite" write operation.
150+
*
151+
* This operation is used to write a file to an existing path.
152+
*
153+
* @extends LLWriteBase
154+
*/
148155
class LLOWrite extends LLWriteBase {
149156
async _run () {
150-
const {
151-
node, actor, immutable,
152-
file, tmp, fsentry_tmp,
153-
message,
154-
} = this.values;
155-
156-
const svc = Context.get('services');
157-
const sizeService = svc.get('sizeService');
158-
const resourceService = svc.get('resourceService');
159-
const svc_fsEntry = svc.get('fsEntryService');
160-
const svc_event = svc.get('event');
157+
const node = this.values.node;
161158

162-
// TODO: fs:decouple-versions
163-
// add version hook externally so LLCWrite doesn't
164-
// need direct database access
165-
const db = svc.get('database').get(DB_WRITE, 'filesystem');
159+
// Embed fields into this.context
160+
this.context.set('immutable', this.values.immutable);
161+
this.context.set('tmp', this.values.tmp);
162+
this.context.set('fsentry_tmp', this.values.fsentry_tmp);
163+
this.context.set('message', this.values.message);
164+
this.context.set('actor', this.values.actor);
165+
this.context.set('app_id', this.values.app_id);
166166

167167
// TODO: Add symlink write
168168
if ( ! await node.exists() ) {
169169
// TODO: different class of errors for low-level operations
170170
throw APIError.create('subject_does_not_exist');
171171
}
172172

173-
const svc_acl = this.context.get('services').get('acl');
174-
if ( ! await svc_acl.check(actor, node, 'write') ) {
175-
throw await svc_acl.get_safe_acl_error(actor, node, 'write');
176-
}
177-
178-
const uid = await node.get('uid');
179-
180-
const bucket_region = node.entry.bucket_region;
181-
const bucket = node.entry.bucket;
182-
183-
const state_upload = await this._storage_upload({
184-
uuid: node.entry.uuid,
185-
bucket, bucket_region, file,
186-
tmp: {
187-
...tmp,
188-
path: await node.get('path'),
189-
}
190-
});
191-
192-
if ( fsentry_tmp?.thumbnail_promise ) {
193-
fsentry_tmp.thumbnail = await fsentry_tmp.thumbnail_promise;
194-
delete fsentry_tmp.thumbnail_promise;
195-
}
196-
197-
const ts = Math.round(Date.now() / 1000);
198-
const raw_fsentry_delta = {
199-
modified: ts,
200-
accessed: ts,
201-
size: file.size,
202-
...fsentry_tmp,
203-
};
204-
205-
resourceService.register({
206-
uid,
207-
status: RESOURCE_STATUS_PENDING_CREATE,
208-
});
209-
210-
const filesize = file.size;
211-
sizeService.change_usage(actor.type.user.id, filesize);
212-
213-
const entryOp = await svc_fsEntry.update(uid, raw_fsentry_delta);
214-
215-
// depends on fsentry, does not depend on S3
216-
(async () => {
217-
await entryOp.awaitDone();
218-
this.log.debug('[owrite] finished creating fsentry', { uid })
219-
resourceService.free(uid);
220-
svc_event.emit('fs.written.file', {
221-
node,
222-
context: this.context,
223-
});
224-
})();
225-
226-
state_upload.post_insert({
227-
db, user: actor.type.user, node, uid, message, ts,
228-
});
229-
230-
const svc_fileCache = this.context.get('services').get('file-cache');
231-
await svc_fileCache.invalidate(node);
232-
233-
svc_event.emit('fs.write.file', {
234-
node,
173+
return await node.provider.write_overwrite({
235174
context: this.context,
175+
node: node,
176+
file: this.values.file,
236177
});
237-
238-
return node;
239178
}
240179
}
241180

181+
/**
182+
* The "non-overwrite" write operation.
183+
*
184+
* This operation is used to write a file to a non-existent path.
185+
*
186+
* @extends LLWriteBase
187+
*/
242188
class LLCWrite extends LLWriteBase {
243189
static MODULES = {
244190
_path: require('path'),
@@ -247,144 +193,26 @@ class LLCWrite extends LLWriteBase {
247193
}
248194

249195
async _run () {
250-
const { _path, uuidv4, config } = this.modules;
251-
const {
252-
parent, name, immutable,
253-
file, tmp, fsentry_tmp,
254-
message,
255-
256-
actor: actor_let,
257-
app_id,
258-
} = this.values;
259-
let actor = actor_let;
260-
261-
const svc = Context.get('services');
262-
const sizeService = svc.get('sizeService');
263-
const resourceService = svc.get('resourceService');
264-
const svc_fsEntry = svc.get('fsEntryService');
265-
const svc_event = svc.get('event');
266-
const fs = svc.get('filesystem');
267-
268-
// TODO: fs:decouple-versions
269-
// add version hook externally so LLCWrite doesn't
270-
// need direct database access
271-
const db = svc.get('database').get(DB_WRITE, 'filesystem');
272-
273-
const uid = uuidv4();
274-
this.field('fsentry-uid', uid);
196+
const parent = this.values.parent;
275197

276-
// determine bucket region
277-
let bucket_region = config.s3_region ?? config.region;
278-
let bucket = config.s3_bucket;
198+
// Embed fields into this.context
199+
this.context.set('immutable', this.values.immutable);
200+
this.context.set('tmp', this.values.tmp);
201+
this.context.set('fsentry_tmp', this.values.fsentry_tmp);
202+
this.context.set('message', this.values.message);
203+
this.context.set('actor', this.values.actor);
204+
this.context.set('app_id', this.values.app_id);
279205

280-
this.checkpoint('before acl');
281206
if ( ! await parent.exists() ) {
282207
throw APIError.create('subject_does_not_exist');
283208
}
284209

285-
const svc_acl = this.context.get('services').get('acl');
286-
actor = actor ?? Context.get('actor');
287-
if ( ! await svc_acl.check(actor, parent, 'write') ) {
288-
throw await svc_acl.get_safe_acl_error(actor, parent, 'write');
289-
}
290-
291-
this.checkpoint('before storage upload');
292-
293-
const storage_resp = await this._storage_upload({
294-
uuid: uid,
295-
bucket, bucket_region, file,
296-
tmp: {
297-
...tmp,
298-
path: _path.join(await parent.get('path'), name),
299-
}
300-
});
301-
302-
this.checkpoint('after storage upload');
303-
304-
fsentry_tmp.thumbnail = await fsentry_tmp.thumbnail_promise;
305-
delete fsentry_tmp.thumbnail_promise;
306-
307-
this.checkpoint('after thumbnail promise');
308-
309-
const ts = Math.round(Date.now() / 1000);
310-
const raw_fsentry = {
311-
uuid: uid,
312-
is_dir: 0,
313-
user_id: actor.type.user.id,
314-
created: ts,
315-
accessed: ts,
316-
modified: ts,
317-
parent_uid: await parent.get('uid'),
318-
name,
319-
size: file.size,
320-
path: _path.join(await parent.get('path'), name),
321-
...fsentry_tmp,
322-
323-
bucket_region,
324-
bucket,
325-
326-
associated_app_id: app_id ?? null,
327-
};
328-
329-
svc_event.emit('fs.pending.file', {
330-
fsentry: FSNodeContext.sanitize_pending_entry_info(raw_fsentry),
331-
context: this.context,
332-
})
333-
334-
this.checkpoint('after emit pending file');
335-
336-
resourceService.register({
337-
uid,
338-
status: RESOURCE_STATUS_PENDING_CREATE,
339-
});
340-
341-
const filesize = file.size;
342-
sizeService.change_usage(actor.type.user.id, filesize);
343-
344-
this.checkpoint('after change_usage');
345-
346-
const entryOp = await svc_fsEntry.insert(raw_fsentry);
347-
348-
this.checkpoint('after fsentry insert enqueue');
349-
350-
(async () => {
351-
await entryOp.awaitDone();
352-
this.log.debug('finished creating fsentry', { uid })
353-
resourceService.free(uid);
354-
355-
const new_item_node = await fs.node(new NodeUIDSelector(uid));
356-
const new_item = await new_item_node.get('entry');
357-
const store_version_id = storage_resp.VersionId;
358-
if( store_version_id ){
359-
// insert version into db
360-
db.write(
361-
"INSERT INTO `fsentry_versions` (`user_id`, `fsentry_id`, `fsentry_uuid`, `version_id`, `message`, `ts_epoch`) VALUES (?, ?, ?, ?, ?, ?)",
362-
[
363-
actor.type.user.id,
364-
new_item.id,
365-
new_item.uuid,
366-
store_version_id,
367-
message ?? null,
368-
ts,
369-
]
370-
);
371-
}
372-
})();
373-
374-
this.checkpoint('after version IIAFE');
375-
376-
const node = await fs.node(new NodeUIDSelector(uid));
377-
378-
this.checkpoint('after create FSNodeContext');
379-
380-
svc_event.emit('fs.create.file', {
381-
node,
210+
return await parent.provider.write_new({
382211
context: this.context,
212+
parent,
213+
name: this.values.name,
214+
file: this.values.file,
383215
});
384-
385-
this.checkpoint('return result');
386-
387-
return node;
388216
}
389217
}
390218

0 commit comments

Comments
 (0)