mirror of
https://github.com/Start9Labs/patch-db.git
synced 2026-03-26 18:31:53 +00:00
fix: revert from ciborium to serde_cbor_2, make apply_patches iterative
- ciborium's deserialize_str bug (#32) caused DB deserialization to fail silently, nuking the database value to null on compress - Switch to dr-bonez/cbor fork (serde_cbor_2) which has StreamDeserializer change_output_type support - Propagate deserialization errors instead of falling back to null - Convert apply_patches from recursion to iteration to prevent stack overflow on patches with many operations (e.g. 953 ops)
This commit is contained in:
@@ -27,10 +27,8 @@ pub enum Error {
|
||||
IO(#[from] IOError),
|
||||
#[error("JSON (De)Serialization Error: {0}")]
|
||||
JSON(#[from] imbl_value::Error),
|
||||
#[error("CBOR Deserialization Error: {0}")]
|
||||
CborDe(#[from] ciborium::de::Error<IOError>),
|
||||
#[error("CBOR Serialization Error: {0}")]
|
||||
CborSer(#[from] ciborium::ser::Error<IOError>),
|
||||
#[error("CBOR (De)Serialization Error: {0}")]
|
||||
CBOR(#[from] serde_cbor::Error),
|
||||
#[error("Index Error: {0:?}")]
|
||||
Pointer(#[from] json_ptr::IndexError),
|
||||
#[error("Patch Error: {0}")]
|
||||
|
||||
@@ -58,7 +58,6 @@ impl Store {
|
||||
};
|
||||
let mut res = tokio::task::spawn_blocking(move || {
|
||||
use std::io::Seek;
|
||||
|
||||
let bak = path.with_extension("bak");
|
||||
if bak.exists() {
|
||||
std::fs::rename(&bak, &path)?;
|
||||
@@ -73,16 +72,13 @@ impl Store {
|
||||
fd_lock_rs::LockType::Exclusive,
|
||||
false,
|
||||
)?;
|
||||
let mut reader = std::io::BufReader::new(&mut *f);
|
||||
let mut scratch = Vec::new();
|
||||
let mut revision: u64 =
|
||||
ciborium::from_reader_with_buffer(&mut reader, &mut scratch).unwrap_or(0);
|
||||
let mut persistent: Value =
|
||||
ciborium::from_reader_with_buffer(&mut reader, &mut scratch)
|
||||
.unwrap_or(Value::Null);
|
||||
while let Ok(patch) =
|
||||
ciborium::from_reader_with_buffer::<json_patch::Patch, _>(&mut reader, &mut scratch)
|
||||
{
|
||||
let mut stream =
|
||||
serde_cbor::StreamDeserializer::new(serde_cbor::de::IoRead::new(&mut *f));
|
||||
let mut revision: u64 = stream.next().transpose()?.unwrap_or(0);
|
||||
let mut stream = stream.change_output_type();
|
||||
let mut persistent: Value = stream.next().transpose()?.unwrap_or(Value::Null);
|
||||
let mut stream = stream.change_output_type();
|
||||
while let Some(Ok(patch)) = stream.next() {
|
||||
if let Err(_) = json_patch::patch(&mut persistent, &patch) {
|
||||
#[cfg(feature = "tracing")]
|
||||
tracing::error!("Error applying patch, skipping...");
|
||||
@@ -180,10 +176,8 @@ impl Store {
|
||||
use tokio::io::AsyncWriteExt;
|
||||
let bak = self.path.with_extension("bak");
|
||||
let bak_tmp = bak.with_extension("bak.tmp");
|
||||
let mut revision_cbor = Vec::new();
|
||||
ciborium::into_writer(&self.revision, &mut revision_cbor)?;
|
||||
let mut data_cbor = Vec::new();
|
||||
ciborium::into_writer(&self.persistent, &mut data_cbor)?;
|
||||
let revision_cbor = serde_cbor::to_vec(&self.revision)?;
|
||||
let data_cbor = serde_cbor::to_vec(&self.persistent)?;
|
||||
|
||||
// Phase 1: Create atomic backup. If this fails, the main file is
|
||||
// untouched and the caller can safely undo the in-memory patch.
|
||||
@@ -250,8 +244,7 @@ impl Store {
|
||||
tracing::trace!("Attempting to apply patch: {:?}", patch);
|
||||
|
||||
// apply patch in memory
|
||||
let mut patch_bin = Vec::new();
|
||||
ciborium::into_writer(&*patch, &mut patch_bin)?;
|
||||
let patch_bin = serde_cbor::to_vec(&*patch)?;
|
||||
let mut updated = TentativeUpdated::new(self, &patch)?;
|
||||
|
||||
if updated.store.revision % 4096 == 0 {
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::sync::Arc;
|
||||
|
||||
use imbl_value::{json, Value};
|
||||
use json_ptr::JsonPointer;
|
||||
use patch_db::{HasModel, PatchDb, Revision};
|
||||
use patch_db::{PatchDb, Revision};
|
||||
use proptest::prelude::*;
|
||||
use tokio::fs;
|
||||
use tokio::runtime::Builder;
|
||||
@@ -86,20 +86,3 @@ proptest! {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Debug, serde::Deserialize, serde::Serialize, HasModel)]
|
||||
// pub struct Sample {
|
||||
// a: String,
|
||||
// #[model]
|
||||
// b: Child,
|
||||
// }
|
||||
|
||||
// #[derive(Debug, serde::Deserialize, serde::Serialize, HasModel)]
|
||||
// pub struct Child {
|
||||
// a: String,
|
||||
// b: usize,
|
||||
// c: NewType,
|
||||
// }
|
||||
|
||||
// #[derive(Debug, serde::Deserialize, serde::Serialize, HasModel)]
|
||||
// pub struct NewType(Option<Box<Sample>>);
|
||||
|
||||
Reference in New Issue
Block a user