Skip to content

Commit 152d84e

Browse files
committed
Optimize recursive sync logic
1 parent 7d22968 commit 152d84e

File tree

3 files changed

+57
-32
lines changed

3 files changed

+57
-32
lines changed

app/src/components/utils.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,24 @@ const utils = {
339339
&& pathParts.filter(part => !prefixParts.includes(part)).length === 1;
340340
},
341341

342+
/**
343+
* @function isPrefixOfPath
344+
* Predicate function determining if the `path` is a member of or equal to the `prefix` path
345+
* @param {string} prefix The base "folder"
346+
* @param {string} path The "file" to check
347+
* @returns {boolean} True if path is member of prefix. False in all other cases.
348+
*/
349+
isPrefixOfPath(prefix, path) {
350+
if (typeof prefix !== 'string' || typeof path !== 'string') return false;
351+
// path `/photos/holiday/` (represents a folder) and should be an objects in bucket with key `/photos/holiday`
352+
if (prefix === path || prefix + DELIMITER === path) return true;
353+
354+
const pathParts = path.split(DELIMITER).filter(part => part);
355+
const prefixParts = prefix.split(DELIMITER).filter(part => part);
356+
return prefixParts.every((part, i) => pathParts[i] === part)
357+
&& pathParts.filter(part => !prefixParts.includes(part)).length === 1;
358+
},
359+
342360
/**
343361
* @function isTruthy
344362
* Returns true if the element name in the object contains a truthy value

app/src/controllers/sync.js

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const { NIL: SYSTEM_USER } = require('uuid');
22

33
const errorToProblem = require('../components/errorToProblem');
4-
const { addDashesToUuid, getCurrentIdentity, formatS3KeyForCompare, isAtPath } = require('../components/utils');
4+
const { addDashesToUuid, getCurrentIdentity, formatS3KeyForCompare, isPrefixOfPath } = require('../components/utils');
55
const utils = require('../db/models/utils');
66
const log = require('../components/log')(module.filename);
77

@@ -126,31 +126,40 @@ const controller = {
126126
try {
127127
// delete buckets not found in S3 from COMS db
128128
const oldDbBuckets = dbBuckets.filter(b => !s3Keys.includes(b.key));
129-
for (const dbBucket of oldDbBuckets) {
130-
await bucketService.delete(dbBucket.bucketId, trx);
131-
dbBuckets = dbBuckets.filter(b => b.bucketId != dbBucket.bucketId);
132-
}
129+
await Promise.all(
130+
oldDbBuckets.map(dbBucket =>
131+
bucketService.delete(dbBucket.bucketId, trx)
132+
.then(() => {
133+
dbBuckets = dbBuckets.filter(b => b.bucketId !== dbBucket.bucketId);
134+
})
135+
)
136+
);
137+
133138
// Create buckets only found in S3 in COMS db
134139
const newS3Keys = s3Keys.filter(k => !dbBuckets.map(b => b.key).includes(k));
135-
for (const s3Key of newS3Keys) {
136-
const data = {
137-
bucketName: s3Key.substring(s3Key.lastIndexOf('/') + 1),
138-
accessKeyId: parentBucket.accessKeyId,
139-
bucket: parentBucket.bucket,
140-
endpoint: parentBucket.endpoint,
141-
key: s3Key,
142-
secretAccessKey: parentBucket.secretAccessKey,
143-
region: parentBucket.region ?? undefined,
144-
active: parentBucket.active,
145-
userId: parentBucket.createdBy ?? SYSTEM_USER,
146-
// current user has MANAGE perm on parent folder (see route.hasPermission)
147-
// ..so copy all their perms to NEW subfolders
148-
permCodes: currentUserParentBucketPerms
149-
};
140+
await Promise.all(
141+
newS3Keys.map(s3Key => {
142+
const data = {
143+
bucketName: s3Key.substring(s3Key.lastIndexOf('/') + 1),
144+
accessKeyId: parentBucket.accessKeyId,
145+
bucket: parentBucket.bucket,
146+
endpoint: parentBucket.endpoint,
147+
key: s3Key,
148+
secretAccessKey: parentBucket.secretAccessKey,
149+
region: parentBucket.region ?? undefined,
150+
active: parentBucket.active,
151+
userId: parentBucket.createdBy ?? SYSTEM_USER,
152+
// current user has MANAGE perm on parent folder (see route.hasPermission)
153+
// ..so copy all their perms to NEW subfolders
154+
permCodes: currentUserParentBucketPerms
155+
};
156+
return bucketService.create(data, trx)
157+
.then((dbResponse) => {
158+
dbBuckets.push(dbResponse);
159+
});
160+
})
161+
);
150162

151-
const dbResponse = await bucketService.create(data, trx);
152-
dbBuckets.push(dbResponse);
153-
}
154163
return dbBuckets;
155164
}
156165
catch (err) {
@@ -175,6 +184,7 @@ const controller = {
175184
const dbObjects = await objectService.searchObjects({
176185
bucketId: dbBuckets.map(b => b.bucketId)
177186
}, trx);
187+
178188
/**
179189
* merge arrays of objects from COMS db and S3 to form an array of jobs with format:
180190
* [ { path: '/images/img3.jpg', bucketId: '123' }, { path: '/images/album1/img1.jpg', bucketId: '456' } ]
@@ -191,9 +201,7 @@ const controller = {
191201
...s3Objects.DeleteMarkers.map(object => {
192202
return {
193203
path: object.Key,
194-
bucketId: dbBuckets
195-
.filter(b => isAtPath(b.key, object.Key))
196-
.map(b => b.bucketId)[0]
204+
bucketId: dbBuckets.find(b => isPrefixOfPath(b.key, object.Key))?.bucketId
197205
};
198206
}),
199207
// Versions found in S3
@@ -202,15 +210,14 @@ const controller = {
202210
.map(object => {
203211
return {
204212
path: object.Key,
205-
bucketId: dbBuckets
206-
.filter(b => isAtPath(b.key, object.Key))
207-
.map(b => b.bucketId)[0],
208-
// adding current userId will give ALL perms on new objects
213+
bucketId: dbBuckets.find(b => isPrefixOfPath(b.key, object.Key))?.bucketId
214+
// NOTE: adding current userId will give ALL perms on new objects
209215
// and set createdBy on all downstream resources (versions, tags, meta)
210216
// userId: userId
211217
};
212-
})
218+
}),
213219
])];
220+
214221
// merge and remove duplicates
215222
const jobs = [...new Map(objects.map(o => [o.path, o])).values()];
216223

charts/coms/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: common-object-management-service
33
# This is the chart version. This version number should be incremented each time you make changes
44
# to the chart and its templates, including the app version.
55
# Versions are expected to follow Semantic Versioning (https://semver.org/)
6-
version: 2.0.3
6+
version: 2.0.4
77
kubeVersion: ">= 1.13.0"
88
description: A microservice for managing access control to S3 Objects
99
# A chart can be either an 'application' or a 'library' chart.

0 commit comments

Comments
 (0)