Skip to content

Commit b03a364

Browse files
committed
Store editSessions
1 parent 17c777f commit b03a364

File tree

5 files changed

+119
-43
lines changed

5 files changed

+119
-43
lines changed

WORKSPACE.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defaultArgs:
77
jbMarketplacePublishTrigger: "false"
88
publishToJBMarketplace: true
99
localAppVersion: unknown
10-
codeCommit: 663d7021754843f9f3532c556963e31d04fa5231
10+
codeCommit: e32288b4d00abdf4a76efbe8e4a9344d5194bb7c
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

+17-11
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

+35-18
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

+2-2
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

+64-11
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,9 +256,10 @@ 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[] = [];
262+
let oldRevList: string[] | undefined;
255263
const rev = await this.db.insert(
256264
userId,
257265
resourceKey,
@@ -282,12 +290,14 @@ 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) => {});
295+
if (oldRevList && oldRevList.length > 0) {
296+
// sync delete old revs from storage
297+
this.deleteObjects(userId, resourceKey, oldRevList).catch((e) => {});
298+
}
289299
if (!rev) {
290-
res.sendStatus(412);
300+
res.sendStatus(isEditSessionsResource ? 400 : 412);
291301
return;
292302
}
293303
res.setHeader("etag", rev);
@@ -300,11 +310,13 @@ export class CodeSyncService {
300310
res.sendStatus(204);
301311
return;
302312
}
313+
314+
// This endpoint is used to delete settings-sync data only
303315
const userId = req.user.id;
304-
await this.db.delete(userId, async () => {
316+
await this.db.deleteSettingsSyncResources(userId, async () => {
305317
const request = new DeleteRequest();
306318
request.setOwnerId(userId);
307-
request.setPrefix(objectPrefix);
319+
request.setPrefix(getNamePrefix("machines"));
308320
try {
309321
const blobsClient = this.blobsProvider.getDefault();
310322
await util.promisify(blobsClient.delete.bind(blobsClient))(request);
@@ -316,6 +328,47 @@ export class CodeSyncService {
316328

317329
return;
318330
});
331+
router.delete("/v1/resource/:resource/:ref?", async (req, res) => {
332+
if (!User.is(req.user)) {
333+
res.sendStatus(204);
334+
return;
335+
}
336+
337+
// This endpoint is used to delete edit sessions data only
338+
const { resource, ref } = req.params;
339+
if (resource !== "editSessions") {
340+
res.sendStatus(400);
341+
return;
342+
}
343+
344+
const userId = req.user.id;
345+
await this.db.deleteResource(userId, resource, ref, async (ref?: string) => {
346+
const request = new DeleteRequest();
347+
request.setOwnerId(userId);
348+
if (ref) {
349+
request.setExact(toObjectName(resource, ref));
350+
} else {
351+
request.setPrefix(getNamePrefix("editSessions") + resource);
352+
}
353+
try {
354+
const blobsClient = this.blobsProvider.getDefault();
355+
await util.promisify(blobsClient.delete.bind(blobsClient))(request);
356+
} catch (e) {
357+
if (e.code === status.NOT_FOUND) {
358+
return;
359+
}
360+
if (ref) {
361+
log.error({ userId }, "code sync: failed to delete obj", e, {
362+
object: toObjectName(resource, ref),
363+
});
364+
} else {
365+
log.error({ userId }, "code sync: failed to delete", e);
366+
}
367+
}
368+
});
369+
res.sendStatus(200);
370+
});
371+
319372
return router;
320373
}
321374

@@ -358,8 +411,8 @@ export class CodeSyncService {
358411
protected async deleteObjects(userId: string, resourceKey: ServerResource, revs: string[]) {
359412
const tasks = revs.map((rev) =>
360413
this.db
361-
.deleteResource(userId, resourceKey, rev, async (rev: string) => {
362-
const obj = toObjectName(resourceKey, rev);
414+
.deleteResource(userId, resourceKey, rev, async (rev?: string) => {
415+
const obj = toObjectName(resourceKey, rev!);
363416
try {
364417
const request = new DeleteRequest();
365418
request.setOwnerId(userId);

0 commit comments

Comments
 (0)