mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-13 21:14:28 -08:00
Preserve redo log for mutable objects
Replay it during time travel debugging
This commit is contained in:
61
src/runtime/let_multiversion.js
Normal file
61
src/runtime/let_multiversion.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import {Multiversion} from './multiversion.js'
|
||||
|
||||
// https://stackoverflow.com/a/29018745
|
||||
function binarySearch(arr, el, compare_fn) {
|
||||
let m = 0;
|
||||
let n = arr.length - 1;
|
||||
while (m <= n) {
|
||||
let k = (n + m) >> 1;
|
||||
let cmp = compare_fn(el, arr[k]);
|
||||
if (cmp > 0) {
|
||||
m = k + 1;
|
||||
} else if(cmp < 0) {
|
||||
n = k - 1;
|
||||
} else {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
return ~m;
|
||||
}
|
||||
|
||||
export class LetMultiversion extends Multiversion {
|
||||
constructor(cxt, initial) {
|
||||
super(cxt)
|
||||
this.latest = initial
|
||||
this.versions = [{version_number: cxt.version_counter, value: initial}]
|
||||
}
|
||||
|
||||
rollback_if_needed() {
|
||||
if(this.needs_rollback()) {
|
||||
this.latest = this.get_version(this.cxt.version_counter)
|
||||
}
|
||||
}
|
||||
|
||||
get() {
|
||||
this.rollback_if_needed()
|
||||
return this.latest
|
||||
}
|
||||
|
||||
set(value) {
|
||||
this.rollback_if_needed()
|
||||
const version_number = ++this.cxt.version_counter
|
||||
if(this.is_created_during_current_expansion()) {
|
||||
this.versions.push({version_number, value})
|
||||
}
|
||||
this.latest = value
|
||||
}
|
||||
|
||||
get_version(version_number) {
|
||||
if(version_number == null) {
|
||||
throw new Error('illegal state')
|
||||
}
|
||||
const idx = binarySearch(this.versions, version_number, (id, el) => id - el.version_number)
|
||||
if(idx >= 0) {
|
||||
return this.versions[idx].value
|
||||
} else if(idx == -1) {
|
||||
throw new Error('illegal state')
|
||||
} else {
|
||||
return this.versions[-idx - 2].value
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user