mirror of
https://github.com/aljazceru/plugins.git
synced 2025-12-21 15:14:19 +01:00
backup: Add PRAGMA foreign_keys=on when restoring so cascades work
We heavily rely on foreign key constraints to keep the DB consistent and drop dependent objects such as UTXO set entries when we roll back a block. We also need to enable the foreign key constraints when restoring otherwise these dependents are not removed and we run into constraint violations.
This commit is contained in:
@@ -80,26 +80,44 @@ class Backend(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def restore(self, dest: str, remove_existing: bool = False) -> bool:
|
def _db_open(self, dest: str) -> sqlite3.Connection:
|
||||||
"""Restore the backup in this backend to its former glory.
|
db = sqlite3.connect(dest)
|
||||||
"""
|
db.execute("PRAGMA foreign_keys = 1")
|
||||||
|
return db
|
||||||
|
|
||||||
|
def _restore_snapshot(self, snapshot: bytes, dest: str):
|
||||||
if os.path.exists(dest):
|
if os.path.exists(dest):
|
||||||
os.unlink(dest)
|
os.unlink(dest)
|
||||||
db = sqlite3.connect(dest)
|
with open(dest, 'wb') as f:
|
||||||
for c in tqdm(self.stream_changes(), total=self.version):
|
f.write(snapshot)
|
||||||
if c.snapshot is not None:
|
self.db = self._db_open(dest)
|
||||||
if os.path.exists(dest):
|
|
||||||
os.unlink(dest)
|
|
||||||
with open(dest, 'wb') as f:
|
|
||||||
f.write(c.snapshot)
|
|
||||||
db = sqlite3.connect(dest)
|
|
||||||
if c.transaction is not None:
|
|
||||||
cur = db.cursor()
|
|
||||||
for q in c.transaction:
|
|
||||||
cur.execute(q.decode('UTF-8'))
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
return True
|
def _restore_transaction(self, tx: Iterator[bytes]):
|
||||||
|
assert(self.db)
|
||||||
|
cur = self.db.cursor()
|
||||||
|
for q in tx:
|
||||||
|
cur.execute(q.decode('UTF-8'))
|
||||||
|
self.db.commit()
|
||||||
|
|
||||||
|
def restore(self, dest: str, remove_existing: bool = False):
|
||||||
|
"""Restore the backup in this backend to its former glory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if os.path.exists(dest):
|
||||||
|
if not remove_existing:
|
||||||
|
raise ValueError(
|
||||||
|
"Destination for backup restore exists: {dest}".format(
|
||||||
|
dest=dest
|
||||||
|
)
|
||||||
|
)
|
||||||
|
os.unlink(dest)
|
||||||
|
|
||||||
|
self.db = self._db_open(dest)
|
||||||
|
for c in tqdm(self.stream_changes()):
|
||||||
|
if c.snapshot is not None:
|
||||||
|
self._restore_snapshot(c.snapshot, dest)
|
||||||
|
if c.transaction is not None:
|
||||||
|
self._restore_transaction(c.transaction)
|
||||||
|
|
||||||
|
|
||||||
class FileBackend(Backend):
|
class FileBackend(Backend):
|
||||||
|
|||||||
Reference in New Issue
Block a user