Add Replica::num_undo_points and exclude undo points from num_operations

This commit is contained in:
Dustin J. Mitchell 2022-07-17 23:22:27 +00:00
parent 17726ddfe4
commit 4a1556ccb9
6 changed files with 79 additions and 6 deletions

View file

@ -109,7 +109,7 @@ static void test_replica_working_set(void) {
tc_working_set_free(ws); tc_working_set_free(ws);
TEST_ASSERT_EQUAL(19, tc_replica_num_local_operations(rep)); TEST_ASSERT_EQUAL(18, tc_replica_num_local_operations(rep));
tc_replica_free(rep); tc_replica_free(rep);
} }

View file

@ -360,7 +360,8 @@ pub unsafe extern "C" fn tc_replica_undo(rep: *mut TCReplica, undone_out: *mut i
) )
} }
/// Get the number of local, un-synchronized operations, or -1 on error /// Get the number of local, un-synchronized operations (not including undo points), or -1 on
/// error.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn tc_replica_num_local_operations(rep: *mut TCReplica) -> i64 { pub unsafe extern "C" fn tc_replica_num_local_operations(rep: *mut TCReplica) -> i64 {
wrap( wrap(
@ -373,6 +374,19 @@ pub unsafe extern "C" fn tc_replica_num_local_operations(rep: *mut TCReplica) ->
) )
} }
/// Get the number of undo points (number of undo calls possible), or -1 on error.
#[no_mangle]
pub unsafe extern "C" fn tc_replica_num_undo_points(rep: *mut TCReplica) -> i64 {
wrap(
rep,
|rep| {
let count = rep.num_undo_points()? as i64;
Ok(count)
},
-1,
)
}
/// Add an UndoPoint, if one has not already been added by this Replica. This occurs automatically /// Add an UndoPoint, if one has not already been added by this Replica. This occurs automatically
/// when a change is made. The `force` flag allows forcing a new UndoPoint even if one has already /// when a change is made. The `force` flag allows forcing a new UndoPoint even if one has already
/// been created by this Replica, and may be useful when a Replica instance is held for a long time /// been created by this Replica, and may be useful when a Replica instance is held for a long time

View file

@ -558,10 +558,16 @@ TCResult tc_replica_sync(struct TCReplica *rep, struct TCServer *server, bool av
TCResult tc_replica_undo(struct TCReplica *rep, int32_t *undone_out); TCResult tc_replica_undo(struct TCReplica *rep, int32_t *undone_out);
/** /**
* Get the number of local, un-synchronized operations, or -1 on error * Get the number of local, un-synchronized operations (not including undo points), or -1 on
* error.
*/ */
int64_t tc_replica_num_local_operations(struct TCReplica *rep); int64_t tc_replica_num_local_operations(struct TCReplica *rep);
/**
* Get the number of undo points (number of undo calls possible), or -1 on error.
*/
int64_t tc_replica_num_undo_points(struct TCReplica *rep);
/** /**
* Add an UndoPoint, if one has not already been added by this Replica. This occurs automatically * Add an UndoPoint, if one has not already been added by this Replica. This occurs automatically
* when a change is made. The `force` flag allows forcing a new UndoPoint even if one has already * when a change is made. The `force` flag allows forcing a new UndoPoint even if one has already

View file

@ -259,6 +259,11 @@ impl Replica {
pub fn num_local_operations(&mut self) -> anyhow::Result<usize> { pub fn num_local_operations(&mut self) -> anyhow::Result<usize> {
self.taskdb.num_operations() self.taskdb.num_operations()
} }
/// Get the number of undo points available (number of times `undo` will succeed).
pub fn num_undo_points(&mut self) -> anyhow::Result<usize> {
self.taskdb.num_undo_points()
}
} }
#[cfg(test)] #[cfg(test)]
@ -405,7 +410,11 @@ mod tests {
] ]
); );
assert_eq!(rep.num_local_operations().unwrap(), 10); // num_local_operations includes all but the undo point
assert_eq!(rep.num_local_operations().unwrap(), 9);
// num_undo_points includes only the undo point
assert_eq!(rep.num_undo_points().unwrap(), 1);
} }
#[test] #[test]

View file

@ -59,6 +59,11 @@ impl ReplicaOp {
} }
} }
/// Determine whether this is an undo point.
pub fn is_undo_point(&self) -> bool {
self == &Self::UndoPoint
}
/// Generate a sequence of SyncOp's to reverse the effects of this ReplicaOp. /// Generate a sequence of SyncOp's to reverse the effects of this ReplicaOp.
pub fn reverse_ops(self) -> Vec<SyncOp> { pub fn reverse_ops(self) -> Vec<SyncOp> {
match self { match self {

View file

@ -128,10 +128,25 @@ impl TaskDb {
undo::undo(txn.as_mut()) undo::undo(txn.as_mut())
} }
/// Get the number of un-synchronized operations in storage. /// Get the number of un-synchronized operations in storage, excluding undo
/// operations.
pub fn num_operations(&mut self) -> anyhow::Result<usize> { pub fn num_operations(&mut self) -> anyhow::Result<usize> {
let mut txn = self.storage.txn().unwrap(); let mut txn = self.storage.txn().unwrap();
txn.num_operations() Ok(txn
.operations()?
.iter()
.filter(|o| !o.is_undo_point())
.count())
}
/// Get the number of (un-synchronized) undo points in storage.
pub fn num_undo_points(&mut self) -> anyhow::Result<usize> {
let mut txn = self.storage.txn().unwrap();
Ok(txn
.operations()?
.iter()
.filter(|o| o.is_undo_point())
.count())
} }
// functions for supporting tests // functions for supporting tests
@ -196,6 +211,30 @@ mod tests {
assert_eq!(db.operations(), vec![ReplicaOp::UndoPoint]); assert_eq!(db.operations(), vec![ReplicaOp::UndoPoint]);
} }
#[test]
fn test_num_operations() {
let mut db = TaskDb::new_inmemory();
db.apply(SyncOp::Create {
uuid: Uuid::new_v4(),
})
.unwrap();
db.add_undo_point().unwrap();
db.apply(SyncOp::Create {
uuid: Uuid::new_v4(),
})
.unwrap();
assert_eq!(db.num_operations().unwrap(), 2);
}
#[test]
fn test_num_undo_points() {
let mut db = TaskDb::new_inmemory();
db.add_undo_point().unwrap();
assert_eq!(db.num_undo_points().unwrap(), 1);
db.add_undo_point().unwrap();
assert_eq!(db.num_undo_points().unwrap(), 2);
}
fn newdb() -> TaskDb { fn newdb() -> TaskDb {
TaskDb::new(Box::new(InMemoryStorage::new())) TaskDb::new(Box::new(InMemoryStorage::new()))
} }