Skip to content

Commit 8d4c41c

Browse files
fix snapshot deadlock and cleanup mutex in createSession (#780)
* fix snapshot deadlock and cleanup mutex in createSession * remove faulty optimisatino * review * return treeInfo if no atom * with dep update not needed --------- Co-authored-by: Christophe Diederichs <chm-diederichs@protonmail.com>
1 parent f1feb12 commit 8d4c41c

File tree

2 files changed

+49
-54
lines changed

2 files changed

+49
-54
lines changed

index.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,16 +376,12 @@ class Hypercore extends EventEmitter {
376376
const state = this.state
377377

378378
if (opts.atom) {
379-
await parentState.mutex.lock()
380379
this.state = await parentState.createSession(null, false, opts.atom)
381-
parentState.mutex.unlock()
382380
if (state) state.unref()
383381
} else if (opts.name) {
384382
// todo: need to make named sessions safe before ready
385383
// atm we always copy the state in passCapabilities
386-
await parentState.mutex.lock()
387384
this.state = await parentState.createSession(opts.name, !!opts.overwrite, null)
388-
parentState.mutex.unlock()
389385
if (state) state.unref() // ref'ed above in setup session
390386
}
391387

lib/session-state.js

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ class SessionState {
124124
}
125125

126126
async _updateSnapshotStorage(storage) {
127-
if (!this.atomized || !this.atomized.flushing) return this.treeInfo()
128-
await this.atomized.flushed()
127+
while (this.atomized && this.atomized.flushing) await this.atomized.flushed()
129128

130129
let rx = storage.read()
131130
const headPromise = rx.getHead()
@@ -206,16 +205,10 @@ class SessionState {
206205
}
207206

208207
async snapshot() {
209-
try {
210-
await this.mutex.lock()
211-
212-
const storage = this.storage.snapshot()
213-
const treeInfo = await this._updateSnapshotStorage(storage)
208+
const storage = this.storage.snapshot()
209+
const treeInfo = await this._updateSnapshotStorage(storage)
214210

215-
return new SessionState(this.core, null, storage, treeInfo, this.name)
216-
} finally {
217-
this._unlock()
218-
}
211+
return new SessionState(this.core, null, storage, treeInfo, this.name)
219212
}
220213

221214
updateDependency(tx, length) {
@@ -1137,56 +1130,62 @@ class SessionState {
11371130
}
11381131

11391132
async createSession(name, overwrite, atom) {
1140-
let storage = null
1141-
let treeInfo = null
1133+
await this.mutex.lock()
11421134

1143-
if (!atom && !overwrite && this.storage) {
1144-
storage = await this.storage.resumeSession(name)
1135+
try {
1136+
let storage = null
1137+
let treeInfo = null
11451138

1146-
if (storage !== null) treeInfo = (await getCoreHead(storage)) || getDefaultTree()
1147-
}
1139+
if (!atom && !overwrite && this.storage) {
1140+
storage = await this.storage.resumeSession(name)
11481141

1149-
const length = treeInfo ? treeInfo.length : this.length
1142+
if (storage !== null) treeInfo = (await getCoreHead(storage)) || getDefaultTree()
1143+
}
11501144

1151-
if (storage === null) {
1152-
treeInfo = await this._getTreeHeadAt(length)
1145+
const length = treeInfo ? treeInfo.length : this.length
11531146

1154-
if (atom) {
1155-
storage = await this.storage.createAtomicSession(atom, treeInfo)
1156-
} else {
1157-
storage = await this.storage.createSession(name, treeInfo)
1147+
if (storage === null) {
1148+
treeInfo = await this._getTreeHeadAt(length)
1149+
1150+
if (atom) {
1151+
storage = await this.storage.createAtomicSession(atom, treeInfo)
1152+
} else {
1153+
storage = await this.storage.createSession(name, treeInfo)
1154+
}
11581155
}
1159-
}
11601156

1161-
if (this.atomized && atom) {
1162-
throw new Error('Session already atomized')
1163-
}
1157+
if (this.atomized && atom) {
1158+
throw new Error('Session already atomized')
1159+
}
11641160

1165-
const head = {
1166-
fork: this.fork,
1167-
roots:
1168-
length === this.length
1169-
? this.roots.slice()
1170-
: await MerkleTree.getRootsFromStorage(storage, length),
1171-
length,
1172-
prologue: this.prologue,
1173-
signature: length === this.length ? this.signature : null
1174-
}
1161+
const head = {
1162+
fork: this.fork,
1163+
roots:
1164+
length === this.length
1165+
? this.roots.slice()
1166+
: await MerkleTree.getRootsFromStorage(storage, length),
1167+
length,
1168+
prologue: this.prologue,
1169+
signature: length === this.length ? this.signature : null
1170+
}
11751171

1176-
const state = new SessionState(
1177-
this.core,
1178-
atom ? this : null,
1179-
storage,
1180-
head,
1181-
atom ? this.name : name
1182-
)
1172+
const state = new SessionState(
1173+
this.core,
1174+
atom ? this : null,
1175+
storage,
1176+
head,
1177+
atom ? this.name : name
1178+
)
11831179

1184-
if (atom) {
1185-
this.atomized = atom
1186-
atom.onflush(state._commit.bind(state))
1187-
}
1180+
if (atom) {
1181+
this.atomized = atom
1182+
atom.onflush(state._commit.bind(state))
1183+
}
11881184

1189-
return state
1185+
return state
1186+
} finally {
1187+
this._unlock()
1188+
}
11901189
}
11911190
}
11921191

0 commit comments

Comments
 (0)