Skip to content

Commit 840682d

Browse files
committed
Replication maybe working.
1 parent a84f813 commit 840682d

8 files changed

Lines changed: 689 additions & 5 deletions

File tree

modules/module-slatedb-storage/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './migrations/SlateDBMigrationAgent.js';
12
export * from './module/SlateDBStorageModule.js';
23

34
export * from './storage/storage-index.js';
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { framework, migrations } from '@powersync/service-core';
2+
3+
class SlateDBMigrationLockManager extends framework.locks.AbstractLockManager {
4+
private locked = false;
5+
6+
protected async acquireHandle(): Promise<framework.locks.LockHandle | null> {
7+
if (this.locked) {
8+
return null;
9+
}
10+
this.locked = true;
11+
return {
12+
refresh: async () => {},
13+
release: async () => {
14+
this.locked = false;
15+
}
16+
};
17+
}
18+
}
19+
20+
export class SlateDBMigrationAgent extends migrations.AbstractPowerSyncMigrationAgent {
21+
readonly locks = new SlateDBMigrationLockManager({ name: 'slatedb_migrations' });
22+
23+
private state: framework.MigrationState | undefined;
24+
25+
readonly store: framework.MigrationStore = {
26+
load: async () => this.state,
27+
save: async (state) => {
28+
this.state = state;
29+
},
30+
clear: async () => {
31+
this.state = undefined;
32+
}
33+
};
34+
35+
getInternalScriptsDir(): string {
36+
throw new Error('SlateDB storage has no internal migrations.');
37+
}
38+
39+
override async loadInternalMigrations(): Promise<framework.Migration<migrations.PowerSyncMigrationContext>[]> {
40+
return [];
41+
}
42+
43+
async [Symbol.asyncDispose](): Promise<void> {
44+
this.state = undefined;
45+
}
46+
}

modules/module-slatedb-storage/src/module/SlateDBStorageModule.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { modules, system } from '@powersync/service-core';
22

3+
import { SlateDBMigrationAgent } from '../migrations/SlateDBMigrationAgent.js';
34
import { SlateDBStorageProvider } from '../storage/storage-index.js';
5+
import { isSlateDBStorageConfig } from '../types/types.js';
46

57
export class SlateDBStorageModule extends modules.AbstractModule {
68
constructor() {
@@ -11,6 +13,10 @@ export class SlateDBStorageModule extends modules.AbstractModule {
1113

1214
async initialize(context: system.ServiceContextContainer): Promise<void> {
1315
context.storageEngine.registerProvider(new SlateDBStorageProvider());
16+
17+
if (isSlateDBStorageConfig(context.configuration.storage)) {
18+
context.migrations.registerMigrationAgent(new SlateDBMigrationAgent());
19+
}
1420
}
1521

1622
async teardown(): Promise<void> {

modules/module-slatedb-storage/src/storage/SlateDBBucketStorageFactory.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
SlateDBPersistedReplicationStream,
1111
SlateDBReplicationStreamRecord
1212
} from './SlateDBPersistedSyncConfigContent.js';
13+
import { SlateDBSyncBucketStorage } from './SlateDBSyncBucketStorage.js';
1314

1415
export type SlateDBBucketStorageOptions = {
1516
config: SlateDBStorageConfigDecoded;
@@ -21,6 +22,8 @@ export class SlateDBBucketStorageFactory extends storage.BucketStorageFactory {
2122

2223
readonly replicationStreamNamePrefix: string;
2324
private store: Promise<SlateDBKVStore> | undefined;
25+
private resolvedStore: SlateDBKVStore | undefined;
26+
private activeStorageCache: SlateDBSyncBucketStorage | undefined;
2427

2528
constructor(readonly options: SlateDBBucketStorageOptions) {
2629
super();
@@ -31,14 +34,27 @@ export class SlateDBBucketStorageFactory extends storage.BucketStorageFactory {
3134
this.store ??= SlateDBKVStore.open({
3235
path: this.options.config.path
3336
});
34-
return this.store;
37+
this.resolvedStore ??= await this.store;
38+
return this.resolvedStore;
3539
}
3640

3741
getInstance(
38-
_replicationStream: storage.PersistedReplicationStream,
42+
replicationStream: storage.PersistedReplicationStream,
3943
_options?: storage.GetIntanceOptions
4044
): storage.SyncRulesBucketStorage {
41-
throw notImplemented('getInstance');
45+
if (!(replicationStream instanceof SlateDBPersistedReplicationStream)) {
46+
throw new Error(`Expected SlateDBPersistedReplicationStream`);
47+
}
48+
if (this.activeStorageCache?.replicationStreamId == replicationStream.replicationStreamId) {
49+
return this.activeStorageCache;
50+
}
51+
const store = this.resolvedStore;
52+
if (store == null) {
53+
throw new Error(`SlateDB store has not been initialized`);
54+
}
55+
const instance = new SlateDBSyncBucketStorage(this, store, replicationStream);
56+
this.activeStorageCache = instance;
57+
return instance;
4258
}
4359

4460
async updateSyncRules(_options: storage.UpdateSyncRulesOptions): Promise<storage.PersistedReplicationStream> {
@@ -174,6 +190,7 @@ export class SlateDBBucketStorageFactory extends storage.BucketStorageFactory {
174190
const store = await this.store;
175191
await store[Symbol.asyncDispose]();
176192
this.store = undefined;
193+
this.resolvedStore = undefined;
177194
}
178195
}
179196

modules/module-slatedb-storage/src/storage/SlateDBKVStore.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ export class SlateDBKVStore implements AsyncDisposable {
6363
) {}
6464

6565
static async open(options: SlateDBKVStoreOptions): Promise<SlateDBKVStore> {
66-
await fs.mkdir(options.path, { recursive: true });
66+
const rootPath = path.resolve(options.path);
67+
await fs.mkdir(rootPath, { recursive: true });
6768

6869
const objectStoreUrl = LOCAL_FILE_OBJECT_STORE_URL;
69-
const dbPath = path.join(options.path, options.dbPath ?? DEFAULT_DB_PATH).replace(/^\/+/, '');
70+
const dbPath = path.join(rootPath, options.dbPath ?? DEFAULT_DB_PATH).replace(/^\/+/, '');
7071
const objectStore = ObjectStore.resolve(objectStoreUrl);
7172

7273
const dbBuilder = new DbBuilder(dbPath, objectStore);
@@ -93,6 +94,15 @@ export class SlateDBKVStore implements AsyncDisposable {
9394
await this.db.delete(toKeyBytes(key));
9495
}
9596

97+
async deletePrefix(prefix: SlateDBKey, options: { limit?: number } = {}): Promise<number> {
98+
const deletes: SlateDBWriteOperation[] = [];
99+
for await (const entry of this.scanPrefix(prefix, options)) {
100+
deletes.push({ type: 'delete', key: entry.key });
101+
}
102+
await this.write(deletes);
103+
return deletes.length;
104+
}
105+
96106
async write(operations: SlateDBWriteOperation[]): Promise<void> {
97107
if (operations.length == 0) {
98108
return;

modules/module-slatedb-storage/src/storage/SlateDBPersistedSyncConfigContent.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export interface SlateDBReplicationStreamRecord {
88
state: storage.SyncRuleState;
99
storageVersion: number;
1010
syncConfig: SlateDBSyncConfigRecord;
11+
next_op_id?: string;
12+
last_persisted_op?: string;
13+
resume_lsn?: string | null;
14+
no_checkpoint_before_lsn?: string | null;
1115
snapshot_done?: boolean;
1216
last_checkpoint_lsn: string | null;
1317
last_fatal_error?: string | null;

0 commit comments

Comments
 (0)