About
License
@@ -1237,6 +1237,38 @@
}
}
+ class Deltas {
+ constructor(database)
+ {
+ this.database = new NamespacedDatabase("deltas", database);
+ }
+
+ length()
+ {
+ var n = 0;
+ this.database.forEach((k) => { n += 1; });
+ return n;
+ }
+
+ push(key)
+ {
+ this.database.set(key, 1);
+ }
+
+ pop(key)
+ {
+ this.database.del(key);
+ }
+
+ popEach(foo)
+ {
+ this.database.forEach((key) => {
+ foo(key);
+ this.database.del(key);
+ });
+ }
+ }
+
class MultiDatabase extends Database {
constructor()
{
@@ -1250,24 +1282,97 @@
{
this.databases.push(arguments[i]);
}
+ this.deltas = new Deltas(this.primary());
+ this.scheduleSync();
+ }
+
+ primary()
+ {
+ return this.databases[0];
+ }
+
+ replicas()
+ {
+ return this.databases.slice(1);
+ }
+
+ scheduleSync()
+ {
+ setInterval(() => { this.sync(); }, 15 * 1000);
+ }
+
+ sync()
+ {
+ console.log("syncing to replicas: " + this.pendingSyncCount());
+ this.deltas.popEach((k) => {
+ console.log("syncing to replicas: " + k);
+ this.replicate(k);
+ });
+ console.log("synced to replicas: " + this.pendingSyncCount());
+ this.writePendingSyncCount();
+ }
+
+ pendingSyncCount()
+ {
+ return this.deltas.length();
+ }
+
+ writePendingSyncCount()
+ {
+ var n = this.pendingSyncCount();
+ var s = "(" + n + ")";
+ if (! n)
+ s = ""
+ document.getElementById("pending").innerHTML = s;
+ }
+
+ replicate(k)
+ {
+ var v = this.primary().get(k);
+ this.replicas().forEach((database) => {
+ if (v)
+ database.set(k, v);
+ else
+ database.del(k, v);
+ });
}
get(key) {
- return this.databases[0].get(key);
+ return this.primary().get(key);
}
set(key, value)
{
- this.databases.forEach((database) => {
- database.set(key, value);
- });
+ this.primary().set(key, value);
+ this.deltas.push(key);
+ try
+ {
+ this.replicas().forEach((database) => {
+ database.set(key, value);
+ });
+ this.deltas.pop(key);
+ }
+ catch (e)
+ {
+ console.log("failed to replicate set: " + e);
+ }
}
del(key)
{
- this.databases.forEach((database) => {
- database.del(key, value);
- });
+ this.primary().del(key);
+ this.deltas.push(key);
+ try
+ {
+ this.replicas().forEach((database) => {
+ database.del(key);
+ });
+ this.deltas.pop(key);
+ }
+ catch (e)
+ {
+ console.log("failed to replicate del: " + e);
+ }
}
forEach(foo)
@@ -1290,7 +1395,7 @@
{
if (key.startsWith(this.namespace + "."))
return key.slice(this.namespace.length + 1);
- return key;
+ return null;
}
prefix(key)
@@ -1319,7 +1424,8 @@
{
this.database.forEach((key) => {
var k = this.deprefix(key);
- foo(k);
+ if (k)
+ foo(k);
});
}
}
@@ -1367,7 +1473,6 @@
new NamespacedDatabase("A", new Local()),
new NamespacedDatabase("B", new Local()),
);
- globalStorage = new NamespacedDatabase("B", new Local());
/*
* poor man's error handling -- $fixme