Skip to content

Commit eb9aaa9

Browse files
jeanp413roboquat
authored andcommitted
Store editSessions
1 parent 4b4e1d5 commit eb9aaa9

File tree

5 files changed

+128
-70
lines changed

5 files changed

+128
-70
lines changed

WORKSPACE.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defaultArgs:
77
jbMarketplacePublishTrigger: "false"
88
publishToJBMarketplace: true
99
localAppVersion: unknown
10-
codeCommit: 06783e74552ddefd74c7e02cdcce19054b294469
10+
codeCommit: ca48b16256fad72bc239a27bde3dc78a369aafa6
1111
codeQuality: stable
1212
intellijDownloadUrl: "https://download.jetbrains.com/idea/ideaIU-2022.2.1.tar.gz"
1313
golandDownloadUrl: "https://download.jetbrains.com/go/goland-2022.2.2.tar.gz"

components/gitpod-db/src/typeorm/code-sync-resource-db.spec.db.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export class CodeSyncResourceDBSpec {
2323
}
2424

2525
async after(): Promise<void> {
26-
await this.db.delete(this.userId, () => Promise.resolve());
26+
await this.db.deleteSettingsSyncResources(this.userId, () => Promise.resolve());
2727
}
2828

2929
@test()
@@ -120,7 +120,13 @@ export class CodeSyncResourceDBSpec {
120120
async roundRobinInsert(): Promise<void> {
121121
const kind = "machines";
122122
const expectation: string[] = [];
123-
const doInsert = async (rev: string, oldRevs: string[]) => {
123+
const doInsert = async (newRev: string, oldRevs?: string[]) => {
124+
expectation.unshift(newRev);
125+
126+
if (!oldRevs) {
127+
return;
128+
}
129+
124130
for (let rev of oldRevs) {
125131
await this.db.deleteResource(this.userId, kind, rev, async () => {});
126132
}
@@ -134,23 +140,23 @@ export class CodeSyncResourceDBSpec {
134140

135141
await assertResources();
136142

137-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
138-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
139-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
143+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
144+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
145+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
140146
await assertResources();
141147

142-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
148+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
143149
expectation.length = revLimit;
144150
await assertResources();
145151

146-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
147-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
152+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
153+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
148154
expectation.length = revLimit;
149155
await assertResources();
150156

151-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
152-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
153-
expectation.unshift((await this.db.insert(this.userId, kind, doInsert, { revLimit }))!);
157+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
158+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
159+
await this.db.insert(this.userId, kind, doInsert, { revLimit, overwrite: true });
154160
expectation.length = revLimit;
155161
await assertResources();
156162
}

components/gitpod-db/src/typeorm/code-sync-resource-db.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { TypeORM } from "./typeorm";
1313
export interface CodeSyncInsertOptions {
1414
latestRev?: string;
1515
revLimit?: number;
16+
overwrite?: boolean;
1617
}
1718

1819
@injectable()
@@ -58,14 +59,14 @@ export class CodeSyncResourceDB {
5859
return this.doGetResources(connection.manager, userId, kind);
5960
}
6061

61-
async delete(userId: string, doDelete: () => Promise<void>): Promise<void> {
62+
async deleteSettingsSyncResources(userId: string, doDelete: () => Promise<void>): Promise<void> {
6263
const connection = await this.typeORM.getConnection();
6364
await connection.transaction(async (manager) => {
6465
await manager
6566
.createQueryBuilder()
6667
.update(DBCodeSyncResource)
6768
.set({ deleted: true })
68-
.where("userId = :userId AND deleted = 0", { userId })
69+
.where("userId = :userId AND kind != :kind AND deleted = 0", { userId, kind: "editSessions" })
6970
.execute();
7071
await doDelete();
7172
});
@@ -74,37 +75,53 @@ export class CodeSyncResourceDB {
7475
async deleteResource(
7576
userId: string,
7677
kind: ServerResource,
77-
rev: string,
78-
doDelete: (rev: string) => Promise<void>,
78+
rev: string | undefined,
79+
doDelete: (rev?: string) => Promise<void>,
7980
): Promise<void> {
8081
const connection = await this.typeORM.getConnection();
81-
await connection.transaction(async (manager) => {
82-
await manager
83-
.createQueryBuilder()
84-
.delete()
85-
.from(DBCodeSyncResource)
86-
.where("userId = :userId AND kind = :kind AND rev = :rev", { userId, kind, rev: rev })
87-
.execute();
88-
await doDelete(rev);
89-
});
82+
if (rev) {
83+
await connection.transaction(async (manager) => {
84+
await manager
85+
.createQueryBuilder()
86+
.delete()
87+
.from(DBCodeSyncResource)
88+
.where("userId = :userId AND kind = :kind AND rev = :rev", { userId, kind, rev })
89+
.execute();
90+
await doDelete(rev);
91+
});
92+
} else {
93+
await connection.transaction(async (manager) => {
94+
await manager
95+
.createQueryBuilder()
96+
.update(DBCodeSyncResource)
97+
.set({ deleted: true })
98+
.where("userId = :userId AND kind = :kind", { userId, kind })
99+
.execute();
100+
await doDelete();
101+
});
102+
}
90103
}
91104

92105
async insert(
93106
userId: string,
94107
kind: ServerResource,
95-
doInsert: (rev: string, oldRevs: string[]) => Promise<void>,
108+
doInsert: (rev: string, oldRevs?: string[]) => Promise<void>,
96109
params?: CodeSyncInsertOptions,
97110
): Promise<string | undefined> {
98111
const connection = await this.typeORM.getConnection();
99112
return await connection.transaction(async (manager) => {
100113
let latest: DBCodeSyncResource | undefined;
101-
let toDeleted: DBCodeSyncResource[] = [];
114+
let toDeleted: DBCodeSyncResource[] | undefined;
102115
if (params?.revLimit) {
103116
const resources = await this.doGetResources(manager, userId, kind);
104117
latest = resources[0];
105118
if (resources.length >= params.revLimit) {
106-
// delete + 1 to insert instead of update
107-
toDeleted = resources.splice(params?.revLimit - 1);
119+
if (params.overwrite) {
120+
// delete + 1 to insert instead of update
121+
toDeleted = resources.splice(params?.revLimit - 1);
122+
} else {
123+
return undefined;
124+
}
108125
}
109126
} else {
110127
latest = await this.doGetResource(manager, userId, kind, "latest");
@@ -122,7 +139,7 @@ export class CodeSyncResourceDB {
122139
.execute();
123140
await doInsert(
124141
rev,
125-
toDeleted.map((e) => e.rev),
142+
toDeleted?.map((e) => e.rev),
126143
);
127144
return rev;
128145
});

components/gitpod-db/src/typeorm/entity/db-code-sync-resource.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export interface IUserDataManifest {
4040
//readonly ref: string;
4141
}
4242

43-
export type ServerResource = SyncResource | "machines";
44-
export const ALL_SERVER_RESOURCES: ServerResource[] = [...ALL_SYNC_RESOURCES, "machines"];
43+
export type ServerResource = SyncResource | "machines" | "editSessions" | "profiles";
44+
export const ALL_SERVER_RESOURCES: ServerResource[] = [...ALL_SYNC_RESOURCES, "machines", "editSessions", "profiles"];
4545

4646
@Entity()
4747
@Index("ind_dbsync", ["created"]) // DBSync

components/server/src/code-sync/code-sync-service.ts

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,16 @@ export type CodeSyncConfig = Partial<{
4949
};
5050
}>;
5151

52-
const objectPrefix = "code-sync/";
52+
function getNamePrefix(resource: ServerResource) {
53+
if (resource === "editSessions") {
54+
return "edit-sessions/";
55+
} else {
56+
return "code-sync/";
57+
}
58+
}
59+
5360
function toObjectName(resource: ServerResource, rev: string): string {
54-
return objectPrefix + resource + "/" + rev;
61+
return getNamePrefix(resource) + resource + "/" + rev;
5562
}
5663

5764
const fromTheiaRev = "from-theia";
@@ -249,10 +256,11 @@ export class CodeSyncService {
249256
resourceKey === "machines"
250257
? 1
251258
: config.resources?.[resourceKey]?.revLimit || config?.revLimit || defaultRevLimit;
259+
const isEditSessionsResource = resourceKey === "editSessions";
252260
const userId = req.user.id;
253261
const contentType = req.headers["content-type"] || "*/*";
254-
let oldRevList: string[] = [];
255-
const rev = await this.db.insert(
262+
let oldRevList: string[] | undefined;
263+
const newRev = await this.db.insert(
256264
userId,
257265
resourceKey,
258266
async (rev, oldRevs) => {
@@ -282,15 +290,19 @@ export class CodeSyncService {
282290
}
283291
oldRevList = oldRevs;
284292
},
285-
{ latestRev, revLimit },
293+
{ latestRev, revLimit, overwrite: !isEditSessionsResource },
286294
);
287-
// sync delete old revs from storage
288-
this.deleteObjects(userId, resourceKey, oldRevList).catch((e) => {});
289-
if (!rev) {
290-
res.sendStatus(412);
295+
if (oldRevList && oldRevList.length > 0) {
296+
// sync delete old revs from storage
297+
Promise.allSettled(oldRevList.map((rev) => this.deleteResource(userId, resourceKey, rev))).catch(
298+
() => {},
299+
);
300+
}
301+
if (!newRev) {
302+
res.sendStatus(isEditSessionsResource ? 400 : 412);
291303
return;
292304
}
293-
res.setHeader("etag", rev);
305+
res.setHeader("etag", newRev);
294306
res.sendStatus(200);
295307
return;
296308
},
@@ -300,11 +312,13 @@ export class CodeSyncService {
300312
res.sendStatus(204);
301313
return;
302314
}
315+
316+
// This endpoint is used to delete settings-sync data only
303317
const userId = req.user.id;
304-
await this.db.delete(userId, async () => {
318+
await this.db.deleteSettingsSyncResources(userId, async () => {
305319
const request = new DeleteRequest();
306320
request.setOwnerId(userId);
307-
request.setPrefix(objectPrefix);
321+
request.setPrefix(getNamePrefix("machines"));
308322
try {
309323
const blobsClient = this.blobsProvider.getDefault();
310324
await util.promisify(blobsClient.delete.bind(blobsClient))(request);
@@ -316,6 +330,24 @@ export class CodeSyncService {
316330

317331
return;
318332
});
333+
router.delete("/v1/resource/:resource/:ref?", async (req, res) => {
334+
if (!User.is(req.user)) {
335+
res.sendStatus(204);
336+
return;
337+
}
338+
339+
// This endpoint is used to delete edit sessions data only
340+
const { resource, ref } = req.params;
341+
if (resource !== "editSessions") {
342+
res.sendStatus(400);
343+
return;
344+
}
345+
346+
const userId = req.user.id;
347+
await this.deleteResource(userId, resource, ref);
348+
res.sendStatus(200);
349+
});
350+
319351
return router;
320352
}
321353

@@ -355,32 +387,35 @@ export class CodeSyncService {
355387
return JSON.stringify(extensions);
356388
}
357389

358-
protected async deleteObjects(userId: string, resourceKey: ServerResource, revs: string[]) {
359-
const tasks = revs.map((rev) =>
360-
this.db
361-
.deleteResource(userId, resourceKey, rev, async (rev: string) => {
362-
const obj = toObjectName(resourceKey, rev);
363-
try {
364-
const request = new DeleteRequest();
365-
request.setOwnerId(userId);
366-
request.setExact(obj);
367-
const blobsClient = this.blobsProvider.getDefault();
368-
await util.promisify<DeleteRequest, DeleteResponse>(blobsClient.delete.bind(blobsClient))(
369-
request,
370-
);
371-
} catch (err) {
372-
if (err.code === status.NOT_FOUND) {
373-
return;
374-
}
375-
log.error({ userId }, "code sync: failed to delete obj", err, { object: obj });
376-
throw err;
390+
protected async deleteResource(userId: string, resourceKey: ServerResource, rev?: string) {
391+
try {
392+
await this.db.deleteResource(userId, resourceKey, rev, async (rev?: string) => {
393+
try {
394+
const request = new DeleteRequest();
395+
request.setOwnerId(userId);
396+
if (rev) {
397+
request.setExact(toObjectName(resourceKey, rev));
398+
} else {
399+
request.setPrefix(getNamePrefix(resourceKey) + resourceKey);
377400
}
378-
})
379-
.catch((err) => {
380-
log.error({ userId }, "code sync: failed to delete", err);
381-
}),
382-
);
383-
await Promise.allSettled(tasks);
384-
return;
401+
const blobsClient = this.blobsProvider.getDefault();
402+
await util.promisify<DeleteRequest, DeleteResponse>(blobsClient.delete.bind(blobsClient))(request);
403+
} catch (e) {
404+
if (e.code === status.NOT_FOUND) {
405+
return;
406+
}
407+
throw e;
408+
}
409+
});
410+
} catch (e) {
411+
if (rev) {
412+
log.error({ userId }, "code sync: failed to delete obj", e, {
413+
object: toObjectName(resourceKey, rev),
414+
});
415+
} else {
416+
log.error({ userId }, "code sync: failed to delete", e);
417+
}
418+
throw e;
419+
}
385420
}
386421
}

0 commit comments

Comments
 (0)