Skip to content

Commit 17adca0

Browse files
committed
WIP - #305 - fixes and expanding tests
1 parent 48afda2 commit 17adca0

File tree

5 files changed

+457
-240
lines changed

5 files changed

+457
-240
lines changed

src/vaults/VaultInternal.ts

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,15 @@ class VaultInternal {
188188
protected vaultsNamesDomain: DBDomain;
189189
protected efs: EncryptedFS;
190190
protected efsVault: EncryptedFS;
191-
protected _lock: RWLock = new RWLock();
191+
protected lock: RWLock = new RWLock();
192192

193193
public readLock: ResourceAcquire = async () => {
194-
const release = await this._lock.acquireRead();
194+
const release = await this.lock.acquireRead();
195195
return [async () => release()];
196196
};
197197

198198
public writeLock: ResourceAcquire = async () => {
199-
const release = await this._lock.acquireWrite();
199+
const release = await this.lock.acquireWrite();
200200
return [async () => release()];
201201
};
202202

@@ -301,9 +301,14 @@ class VaultInternal {
301301
);
302302
const vaultDb = await this.db.level(this.vaultIdEncoded, this.vaultsDb);
303303
await vaultDb.clear();
304-
await this.efs.rmdir(this.vaultIdEncoded, {
305-
recursive: true,
306-
});
304+
try {
305+
await this.efs.rmdir(this.vaultIdEncoded, {
306+
recursive: true,
307+
});
308+
} catch (e) {
309+
if (e.code !== 'ENOENT') throw e;
310+
// Otherwise ignore
311+
}
307312
this.logger.info(
308313
`Destroyed ${this.constructor.name} - ${this.vaultIdEncoded}`,
309314
);
@@ -415,7 +420,7 @@ class VaultInternal {
415420
)) != null
416421
) {
417422
// Mirrored vaults are immutable
418-
throw new vaultsErrors.ErrorVaultImmutable();
423+
throw new vaultsErrors.ErrorVaultRemoteDefined();
419424
}
420425
return withF([this.writeLock], async () => {
421426
await this.db.put(
@@ -592,7 +597,7 @@ class VaultInternal {
592597
return withG([this.writeLock], async function* () {
593598
if ((await db.get(vaultDbDomain, VaultInternal.remoteKey)) != null) {
594599
// Mirrored vaults are immutable
595-
throw new vaultsErrors.ErrorVaultImmutable();
600+
throw new vaultsErrors.ErrorVaultRemoteDefined();
596601
}
597602
await db.put(vaultDbDomain, VaultInternal.dirtyKey, true);
598603
const result = yield* g(efsVault);
@@ -607,6 +612,7 @@ class VaultInternal {
607612
});
608613
}
609614

615+
// TODO: this needs to respect the write lock since we are writing to the EFS
610616
@ready(new vaultsErrors.ErrorVaultNotRunning())
611617
public async pullVault({
612618
nodeConnectionManager,
@@ -626,7 +632,7 @@ class VaultInternal {
626632
this.vaultMetadataDbDomain,
627633
VaultInternal.remoteKey,
628634
);
629-
if (remoteInfo == null) throw Error('Vault has no remote to pull from');
635+
if (remoteInfo == null) throw new vaultsErrors.ErrorVaultRemoteUndefined();
630636

631637
if (pullNodeId == null) {
632638
pullNodeId = nodesUtils.decodeNodeId(remoteInfo.remoteNode)!;
@@ -660,17 +666,19 @@ class VaultInternal {
660666
pullVaultNameOrId!,
661667
'pull',
662668
);
663-
await git.pull({
664-
fs: this.efs,
665-
http: { request },
666-
dir: this.vaultDataDir,
667-
gitdir: this.vaultGitDir,
668-
url: `http://`,
669-
ref: 'HEAD',
670-
singleBranch: true,
671-
author: {
672-
name: nodesUtils.encodeNodeId(pullNodeId!),
673-
},
669+
await withF([this.writeLock], async () => {
670+
await git.pull({
671+
fs: this.efs,
672+
http: { request },
673+
dir: this.vaultDataDir,
674+
gitdir: this.vaultGitDir,
675+
url: `http://`,
676+
ref: 'HEAD',
677+
singleBranch: true,
678+
author: {
679+
name: nodesUtils.encodeNodeId(pullNodeId!),
680+
},
681+
});
674682
});
675683
return remoteVaultId;
676684
},

src/vaults/VaultManager.ts

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class VaultManager {
125125
protected vaultsDb: DBLevel;
126126
protected vaultsNamesDbDomain: DBDomain = [...this.vaultsDbDomain, 'names'];
127127
protected vaultsNamesDb: DBLevel;
128+
protected vaultsNamesLock: RWLock = new RWLock();
128129
// VaultId -> VaultMetadata
129130
protected vaultMap: VaultMap = new Map();
130131
protected vaultKey: Buffer;
@@ -307,22 +308,29 @@ class VaultManager {
307308

308309
@ready(new vaultsErrors.ErrorVaultManagerNotRunning())
309310
public async createVault(vaultName: VaultName): Promise<VaultId> {
310-
// Check if the vault name already exists;
311-
if ((await this.getVaultId(vaultName)) != null) {
312-
throw new vaultsErrors.ErrorVaultsVaultDefined();
313-
}
311+
// Adding vault to name map
314312
const vaultId = await this.generateVaultId();
315-
const lock = new RWLock();
316-
const vaultIdString = vaultId.toString() as VaultIdString;
317-
this.vaultMap.set(vaultIdString, { lock });
318-
return await withF([this.getWriteLock(vaultId)], async () => {
319-
// Adding vault to name map
313+
await this.vaultsNamesLock.withWrite(async () => {
314+
const vaultIdBuffer = await this.db.get(
315+
this.vaultsNamesDbDomain,
316+
vaultName,
317+
true,
318+
);
319+
// Check if the vault name already exists;
320+
if (vaultIdBuffer != null) {
321+
throw new vaultsErrors.ErrorVaultsVaultDefined();
322+
}
320323
await this.db.put(
321324
this.vaultsNamesDbDomain,
322325
vaultName,
323326
vaultId.toBuffer(),
324327
true,
325328
);
329+
});
330+
const lock = new RWLock();
331+
const vaultIdString = vaultId.toString() as VaultIdString;
332+
this.vaultMap.set(vaultIdString, { lock });
333+
return await withF([this.getWriteLock(vaultId)], async () => {
326334
// Creating vault
327335
const vault = await VaultInternal.createVaultInternal({
328336
vaultId,
@@ -394,7 +402,9 @@ class VaultManager {
394402
// Removing from map
395403
this.vaultMap.delete(vaultIdString);
396404
// Removing name->id mapping
397-
await this.db.del(this.vaultsNamesDbDomain, vaultName);
405+
await this.vaultsNamesLock.withWrite(async () => {
406+
await this.db.del(this.vaultsNamesDbDomain, vaultName);
407+
});
398408
});
399409
this.logger.info(`Destroyed Vault ${vaultsUtils.encodeVaultId(vaultId)}`);
400410
}
@@ -425,12 +435,7 @@ class VaultManager {
425435
// Stream of vaultName VaultId key value pairs
426436
for await (const vaultNameBuffer of this.vaultsNamesDb.createKeyStream()) {
427437
const vaultName = vaultNameBuffer.toString() as VaultName;
428-
const vaultIdBuffer = await this.db.get(
429-
this.vaultsNamesDbDomain,
430-
vaultNameBuffer,
431-
true,
432-
);
433-
const vaultId = IdInternal.fromBuffer<VaultId>(vaultIdBuffer!);
438+
const vaultId = (await this.getVaultId(vaultName))!;
434439
vaults.set(vaultName, vaultId);
435440
}
436441
return vaults;
@@ -463,13 +468,15 @@ class VaultManager {
463468
];
464469
await this.db.put(vaultDbDomain, VaultInternal.nameKey, newVaultName);
465470
// Updating name->id map
466-
await this.db.del(this.vaultsNamesDbDomain, oldVaultName);
467-
await this.db.put(
468-
this.vaultsNamesDbDomain,
469-
newVaultName,
470-
vaultId.toBuffer(),
471-
true,
472-
);
471+
await this.vaultsNamesLock.withWrite(async () => {
472+
await this.db.del(this.vaultsNamesDbDomain, oldVaultName);
473+
await this.db.put(
474+
this.vaultsNamesDbDomain,
475+
newVaultName,
476+
vaultId.toBuffer(),
477+
true,
478+
);
479+
});
473480
});
474481
}
475482

@@ -478,13 +485,15 @@ class VaultManager {
478485
*/
479486
@ready(new vaultsErrors.ErrorVaultManagerNotRunning())
480487
public async getVaultId(vaultName: VaultName): Promise<VaultId | undefined> {
481-
const vaultIdBuffer = await this.db.get(
482-
this.vaultsNamesDbDomain,
483-
vaultName,
484-
true,
485-
);
486-
if (vaultIdBuffer == null) return;
487-
return IdInternal.fromBuffer<VaultId>(vaultIdBuffer);
488+
return await this.vaultsNamesLock.withWrite(async () => {
489+
const vaultIdBuffer = await this.db.get(
490+
this.vaultsNamesDbDomain,
491+
vaultName,
492+
true,
493+
);
494+
if (vaultIdBuffer == null) return;
495+
return IdInternal.fromBuffer<VaultId>(vaultIdBuffer);
496+
});
488497
}
489498

490499
/**
@@ -769,7 +778,6 @@ class VaultManager {
769778
}
770779

771780
@ready(new vaultsErrors.ErrorVaultManagerNotRunning())
772-
// TODO: write a test for this, check if it actually handles conflicts
773781
protected async generateVaultId(): Promise<VaultId> {
774782
let vaultId = vaultsUtils.generateVaultId();
775783
let i = 0;

src/vaults/errors.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,13 @@ class ErrorVaultReferenceMissing extends ErrorVault {
5454
exitCode = sysexits.USAGE;
5555
}
5656

57-
// Yes it is immutable
58-
// But this is because you don't own the vault right now
57+
class ErrorVaultRemoteDefined extends ErrorVaults {
58+
description = 'Vault is a clone of a remote vault and can not be mutated';
59+
exitCode = sysexits.USAGE;
60+
}
5961

60-
class ErrorVaultImmutable extends ErrorVaults {
61-
description = 'Vault cannot be mutated';
62+
class ErrorVaultRemoteUndefined extends ErrorVaults {
63+
description = 'Vault has no remote set and can not be pulled';
6264
exitCode = sysexits.USAGE;
6365
}
6466

@@ -117,7 +119,8 @@ export {
117119
ErrorVaultDestroyed,
118120
ErrorVaultReferenceInvalid,
119121
ErrorVaultReferenceMissing,
120-
ErrorVaultImmutable,
122+
ErrorVaultRemoteDefined,
123+
ErrorVaultRemoteUndefined,
121124
ErrorVaultsVaultUndefined,
122125
ErrorVaultsVaultDefined,
123126
ErrorVaultsRecursive,

0 commit comments

Comments
 (0)