diff options
| -rw-r--r-- | src/lib.rs | 8 | ||||
| -rw-r--r-- | src/secondary_memtable.rs | 5 | ||||
| -rw-r--r-- | tests/integration.rs | 58 |
3 files changed, 70 insertions, 1 deletions
@@ -224,6 +224,8 @@ impl<Field: Eq + Clone + Debug> DB<Field> { Ok(db) } + /// Insert a record into the database. If the primary key value already exists, + /// the existing record will be replaced by the supplied one. pub fn upsert(&mut self, record: &Record) -> Result<(), io::Error> { debug!("Upserting record: {:?}", record); // Validate the record length @@ -293,7 +295,7 @@ impl<Field: Eq + Clone + Debug> DB<Field> { file.unlock()?; debug!("Record appended to log file, lock released"); - debug!("Updating memtables"); + debug!("Updating primary memtable"); let primary_value = &record.values[self.primary_key_index] @@ -308,6 +310,10 @@ impl<Field: Eq + Clone + Debug> DB<Field> { self.secondary_memtables .iter_mut() .for_each(|secondary_memtable| { + debug!( + "Updating memtable for index on {:?}", + &secondary_memtable.field + ); for (index, (schema_field, _)) in self.config.fields.iter().enumerate() { if schema_field == &secondary_memtable.field { let key = record.values[index] diff --git a/src/secondary_memtable.rs b/src/secondary_memtable.rs index 602db3a..fcf4a7f 100644 --- a/src/secondary_memtable.rs +++ b/src/secondary_memtable.rs @@ -85,9 +85,14 @@ impl<Field: Eq + Clone + Debug> SecondaryMemtable<Field> { match self.records.get_mut(key) { Some(existing) => { + debug!( + "Existing entry found with {} records in the set", + &existing.len() + ); existing.insert(unique_record); } None => { + debug!("No existing entry found, creating one."); let mut set = HashSet::with_capacity(1); set.insert(unique_record); self.records.insert(key.clone(), set); diff --git a/tests/integration.rs b/tests/integration.rs index 41c8807..3e132bc 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -231,3 +231,61 @@ fn test_log_reader_fixture_db1() { _ => false, }); } + +#[test] +#[serial] +fn test_upsert_and_get_from_secondary_memtable() { + let _ = env_logger::builder().is_test(true).try_init(); + let mut db = DB::configure() + .data_dir(TEST_DATA_DIR) + .fields(&vec![ + (Field::Id, RecordFieldType::Int), + (Field::Name, RecordFieldType::String), + (Field::Data, RecordFieldType::Bytes), + ]) + .primary_key(Field::Id) + .secondary_keys(vec![Field::Name]) + .initialize() + .expect("Failed to initialize DB instance"); + + // Insert some records + let record0 = Record { + values: vec![ + RecordValue::Int(0), + RecordValue::String("John".to_string()), + RecordValue::Bytes(vec![3, 4, 5]), + ], + }; + db.upsert(&record0).unwrap(); + + let record1 = Record { + values: vec![ + RecordValue::Int(1), + RecordValue::String("John".to_string()), + RecordValue::Bytes(vec![1, 2, 3]), + ], + }; + db.upsert(&record1).unwrap(); + + let record2 = Record { + values: vec![ + RecordValue::Int(2), + RecordValue::String("George".to_string()), + RecordValue::Bytes(vec![1, 2, 3]), + ], + }; + db.upsert(&record2).unwrap(); + + // Delete the DB so that any results must come from a memtable + fs::remove_file(Path::new(TEST_DATA_DIR).join("db")).expect("Failed to delete the DB log file"); + + // There should be 2 Johns + let johns = db + .find_all(&Field::Name, &RecordValue::String("John".to_string())) + .expect("Failed to find all Johns"); + + assert_eq!(johns.len(), 2); + + // Clean up + std::fs::remove_dir_all(TEST_DATA_DIR.to_string()).unwrap(); +} |
