return old trie values on insert and remove (#4053)
* return old trie values on insert and remove * fix json tests
This commit is contained in:
		
							parent
							
								
									20c1d37b59
								
							
						
					
					
						commit
						b4e713efdc
					
				| @ -33,7 +33,7 @@ fn test_trie(json: &[u8], trie: TrieSpec) -> Vec<String> { | |||||||
| 			let key: Vec<u8> = key.into(); | 			let key: Vec<u8> = key.into(); | ||||||
| 			let value: Vec<u8> = value.map_or_else(Vec::new, Into::into); | 			let value: Vec<u8> = value.map_or_else(Vec::new, Into::into); | ||||||
| 			t.insert(&key, &value) | 			t.insert(&key, &value) | ||||||
| 				.expect(&format!("Trie test '{:?}' failed due to internal error", name)) | 				.expect(&format!("Trie test '{:?}' failed due to internal error", name)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if *t.root() != test.root.into() { | 		if *t.root() != test.root.into() { | ||||||
|  | |||||||
| @ -76,18 +76,28 @@ impl<'db> TrieMut for FatDBMut<'db> { | |||||||
| 		self.raw.get(&key.sha3()) | 		self.raw.get(&key.sha3()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<()> { | 	fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<Option<DBValue>> { | ||||||
| 		let hash = key.sha3(); | 		let hash = key.sha3(); | ||||||
| 		self.raw.insert(&hash, value)?; | 		let out = self.raw.insert(&hash, value)?; | ||||||
| 		let db = self.raw.db_mut(); | 		let db = self.raw.db_mut(); | ||||||
|  | 
 | ||||||
|  | 		// don't insert if it doesn't exist.
 | ||||||
|  | 		if out.is_none() { | ||||||
| 			db.emplace(Self::to_aux_key(&hash), DBValue::from_slice(key)); | 			db.emplace(Self::to_aux_key(&hash), DBValue::from_slice(key)); | ||||||
| 		Ok(()) | 		} | ||||||
|  | 		Ok(out) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn remove(&mut self, key: &[u8]) -> super::Result<()> { | 	fn remove(&mut self, key: &[u8]) -> super::Result<Option<DBValue>> { | ||||||
| 		let hash = key.sha3(); | 		let hash = key.sha3(); | ||||||
|  | 		let out = self.raw.remove(&hash)?; | ||||||
|  | 
 | ||||||
|  | 		// don't remove if it already exists.
 | ||||||
|  | 		if out.is_some() { | ||||||
| 			self.raw.db_mut().remove(&Self::to_aux_key(&hash)); | 			self.raw.db_mut().remove(&Self::to_aux_key(&hash)); | ||||||
| 		self.raw.remove(&hash) | 		} | ||||||
|  | 
 | ||||||
|  | 		Ok(out) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -119,13 +119,13 @@ pub trait TrieMut { | |||||||
| 	/// What is the value of the given key in this trie?
 | 	/// What is the value of the given key in this trie?
 | ||||||
| 	fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result<Option<DBValue>> where 'a: 'key; | 	fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result<Option<DBValue>> where 'a: 'key; | ||||||
| 
 | 
 | ||||||
| 	/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
 | 	/// Insert a `key`/`value` pair into the trie. An empty value is equivalent to removing
 | ||||||
| 	/// `key` from the trie.
 | 	/// `key` from the trie. Returns the old value associated with this key, if it existed.
 | ||||||
| 	fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<()>; | 	fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<Option<DBValue>>; | ||||||
| 
 | 
 | ||||||
| 	/// Remove a `key` from the trie. Equivalent to making it equal to the empty
 | 	/// Remove a `key` from the trie. Equivalent to making it equal to the empty
 | ||||||
| 	/// value.
 | 	/// value. Returns the old value associated with this key, if it existed.
 | ||||||
| 	fn remove(&mut self, key: &[u8]) -> Result<()>; | 	fn remove(&mut self, key: &[u8]) -> Result<Option<DBValue>>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// A trie iterator that also supports random access.
 | /// A trie iterator that also supports random access.
 | ||||||
|  | |||||||
| @ -68,11 +68,11 @@ impl<'db> TrieMut for SecTrieDBMut<'db> { | |||||||
| 		self.raw.get(&key.sha3()) | 		self.raw.get(&key.sha3()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<()> { | 	fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<Option<DBValue>> { | ||||||
| 		self.raw.insert(&key.sha3(), value) | 		self.raw.insert(&key.sha3(), value) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn remove(&mut self, key: &[u8]) -> super::Result<()> { | 	fn remove(&mut self, key: &[u8]) -> super::Result<Option<DBValue>> { | ||||||
| 		self.raw.remove(&key.sha3()) | 		self.raw.remove(&key.sha3()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -452,14 +452,16 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// insert a key, value pair into the trie, creating new nodes if necessary.
 | 	/// insert a key, value pair into the trie, creating new nodes if necessary.
 | ||||||
| 	fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: DBValue) -> super::Result<(StorageHandle, bool)> { | 	fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: DBValue, old_val: &mut Option<DBValue>) | ||||||
|  | 		-> super::Result<(StorageHandle, bool)> | ||||||
|  | 	{ | ||||||
| 		let h = match handle { | 		let h = match handle { | ||||||
| 			NodeHandle::InMemory(h) => h, | 			NodeHandle::InMemory(h) => h, | ||||||
| 			NodeHandle::Hash(h) => self.cache(h)?, | 			NodeHandle::Hash(h) => self.cache(h)?, | ||||||
| 		}; | 		}; | ||||||
| 		let stored = self.storage.destroy(h); | 		let stored = self.storage.destroy(h); | ||||||
| 		let (new_stored, changed) = self.inspect(stored, move |trie, stored| { | 		let (new_stored, changed) = self.inspect(stored, move |trie, stored| { | ||||||
| 			trie.insert_inspector(stored, partial, value).map(|a| a.into_action()) | 			trie.insert_inspector(stored, partial, value, old_val).map(|a| a.into_action()) | ||||||
| 		})?.expect("Insertion never deletes."); | 		})?.expect("Insertion never deletes."); | ||||||
| 
 | 
 | ||||||
| 		Ok((self.storage.alloc(new_stored), changed)) | 		Ok((self.storage.alloc(new_stored), changed)) | ||||||
| @ -467,7 +469,9 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 
 | 
 | ||||||
| 	/// the insertion inspector.
 | 	/// the insertion inspector.
 | ||||||
| 	#[cfg_attr(feature = "dev", allow(cyclomatic_complexity))] | 	#[cfg_attr(feature = "dev", allow(cyclomatic_complexity))] | ||||||
| 	fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: DBValue) -> super::Result<InsertAction> { | 	fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: DBValue, old_val: &mut Option<DBValue>) | ||||||
|  | 		-> super::Result<InsertAction> | ||||||
|  | 	{ | ||||||
| 		trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty()); | 		trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty()); | ||||||
| 
 | 
 | ||||||
| 		Ok(match node { | 		Ok(match node { | ||||||
| @ -481,6 +485,8 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 				if partial.is_empty() { | 				if partial.is_empty() { | ||||||
| 					let unchanged = stored_value.as_ref() == Some(&value); | 					let unchanged = stored_value.as_ref() == Some(&value); | ||||||
| 					let branch = Node::Branch(children, Some(value)); | 					let branch = Node::Branch(children, Some(value)); | ||||||
|  | 					*old_val = stored_value; | ||||||
|  | 
 | ||||||
| 					match unchanged { | 					match unchanged { | ||||||
| 						true => InsertAction::Restore(branch), | 						true => InsertAction::Restore(branch), | ||||||
| 						false => InsertAction::Replace(branch), | 						false => InsertAction::Replace(branch), | ||||||
| @ -490,7 +496,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					let partial = partial.mid(1); | 					let partial = partial.mid(1); | ||||||
| 					if let Some(child) = children[idx].take() { | 					if let Some(child) = children[idx].take() { | ||||||
| 						// original had something there. recurse down into it.
 | 						// original had something there. recurse down into it.
 | ||||||
| 						let (new_child, changed) = self.insert_at(child, partial, value)?; | 						let (new_child, changed) = self.insert_at(child, partial, value, old_val)?; | ||||||
| 						children[idx] = Some(new_child.into()); | 						children[idx] = Some(new_child.into()); | ||||||
| 						if !changed { | 						if !changed { | ||||||
| 							// the new node we composed didn't change. that means our branch is untouched too.
 | 							// the new node we composed didn't change. that means our branch is untouched too.
 | ||||||
| @ -511,7 +517,10 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 				if cp == existing_key.len() && cp == partial.len() { | 				if cp == existing_key.len() && cp == partial.len() { | ||||||
| 					trace!(target: "trie", "equivalent-leaf: REPLACE"); | 					trace!(target: "trie", "equivalent-leaf: REPLACE"); | ||||||
| 					// equivalent leaf.
 | 					// equivalent leaf.
 | ||||||
| 					match stored_value == value { | 					let unchanged = stored_value == value; | ||||||
|  | 					*old_val = Some(stored_value); | ||||||
|  | 
 | ||||||
|  | 					match unchanged { | ||||||
| 						// unchanged. restore
 | 						// unchanged. restore
 | ||||||
| 						true => InsertAction::Restore(Node::Leaf(encoded.clone(), value)), | 						true => InsertAction::Restore(Node::Leaf(encoded.clone(), value)), | ||||||
| 						false => InsertAction::Replace(Node::Leaf(encoded.clone(), value)), | 						false => InsertAction::Replace(Node::Leaf(encoded.clone(), value)), | ||||||
| @ -533,7 +542,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					}; | 					}; | ||||||
| 
 | 
 | ||||||
| 					// always replace because whatever we get out here is not the branch we started with.
 | 					// always replace because whatever we get out here is not the branch we started with.
 | ||||||
| 					let branch_action = self.insert_inspector(branch, partial, value)?.unwrap_node(); | 					let branch_action = self.insert_inspector(branch, partial, value, old_val)?.unwrap_node(); | ||||||
| 					InsertAction::Replace(branch_action) | 					InsertAction::Replace(branch_action) | ||||||
| 				} else if cp == existing_key.len() { | 				} else if cp == existing_key.len() { | ||||||
| 				    trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); | 				    trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); | ||||||
| @ -542,7 +551,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					// make a stub branch and an extension.
 | 					// make a stub branch and an extension.
 | ||||||
| 					let branch = Node::Branch(empty_children(), Some(stored_value)); | 					let branch = Node::Branch(empty_children(), Some(stored_value)); | ||||||
| 					// augment the new branch.
 | 					// augment the new branch.
 | ||||||
| 					let branch = self.insert_inspector(branch, partial.mid(cp), value)?.unwrap_node(); | 					let branch = self.insert_inspector(branch, partial.mid(cp), value, old_val)?.unwrap_node(); | ||||||
| 
 | 
 | ||||||
| 					// always replace since we took a leaf and made an extension.
 | 					// always replace since we took a leaf and made an extension.
 | ||||||
| 					let branch_handle = self.storage.alloc(Stored::New(branch)).into(); | 					let branch_handle = self.storage.alloc(Stored::New(branch)).into(); | ||||||
| @ -553,9 +562,10 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					// partially-shared prefix for an extension.
 | 					// partially-shared prefix for an extension.
 | ||||||
| 					// start by making a leaf.
 | 					// start by making a leaf.
 | ||||||
| 					let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value); | 					let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value); | ||||||
|  | 
 | ||||||
| 					// augment it. this will result in the Leaf -> cp == 0 routine,
 | 					// augment it. this will result in the Leaf -> cp == 0 routine,
 | ||||||
| 					// which creates a branch.
 | 					// which creates a branch.
 | ||||||
| 					let augmented_low = self.insert_inspector(low, partial.mid(cp), value)?.unwrap_node(); | 					let augmented_low = self.insert_inspector(low, partial.mid(cp), value, old_val)?.unwrap_node(); | ||||||
| 
 | 
 | ||||||
| 					// make an extension using it. this is a replacement.
 | 					// make an extension using it. this is a replacement.
 | ||||||
| 					InsertAction::Replace(Node::Extension( | 					InsertAction::Replace(Node::Extension( | ||||||
| @ -586,7 +596,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					}; | 					}; | ||||||
| 
 | 
 | ||||||
| 					// continue inserting.
 | 					// continue inserting.
 | ||||||
| 					let branch_action = self.insert_inspector(Node::Branch(children, None), partial, value)?.unwrap_node(); | 					let branch_action = self.insert_inspector(Node::Branch(children, None), partial, value, old_val)?.unwrap_node(); | ||||||
| 					InsertAction::Replace(branch_action) | 					InsertAction::Replace(branch_action) | ||||||
| 				} else if cp == existing_key.len() { | 				} else if cp == existing_key.len() { | ||||||
| 					trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); | 					trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); | ||||||
| @ -594,7 +604,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					// fully-shared prefix.
 | 					// fully-shared prefix.
 | ||||||
| 
 | 
 | ||||||
| 					// insert into the child node.
 | 					// insert into the child node.
 | ||||||
| 					let (new_child, changed) = self.insert_at(child_branch, partial.mid(cp), value)?; | 					let (new_child, changed) = self.insert_at(child_branch, partial.mid(cp), value, old_val)?; | ||||||
| 					let new_ext = Node::Extension(existing_key.encoded(false), new_child.into()); | 					let new_ext = Node::Extension(existing_key.encoded(false), new_child.into()); | ||||||
| 
 | 
 | ||||||
| 					// if the child branch wasn't changed, meaning this extension remains the same.
 | 					// if the child branch wasn't changed, meaning this extension remains the same.
 | ||||||
| @ -608,7 +618,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 					// partially-shared.
 | 					// partially-shared.
 | ||||||
| 					let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch); | 					let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch); | ||||||
| 					// augment the extension. this will take the cp == 0 path, creating a branch.
 | 					// augment the extension. this will take the cp == 0 path, creating a branch.
 | ||||||
| 					let augmented_low = self.insert_inspector(low, partial.mid(cp), value)?.unwrap_node(); | 					let augmented_low = self.insert_inspector(low, partial.mid(cp), value, old_val)?.unwrap_node(); | ||||||
| 
 | 
 | ||||||
| 					// always replace, since this extension is not the one we started with.
 | 					// always replace, since this extension is not the one we started with.
 | ||||||
| 					// this is known because the partial key is only the common prefix.
 | 					// this is known because the partial key is only the common prefix.
 | ||||||
| @ -622,7 +632,9 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// Remove a node from the trie based on key.
 | 	/// Remove a node from the trie based on key.
 | ||||||
| 	fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice) -> super::Result<Option<(StorageHandle, bool)>> { | 	fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice, old_val: &mut Option<DBValue>) | ||||||
|  | 		-> super::Result<Option<(StorageHandle, bool)>> | ||||||
|  | 	{ | ||||||
| 		let stored = match handle { | 		let stored = match handle { | ||||||
| 			NodeHandle::InMemory(h) => self.storage.destroy(h), | 			NodeHandle::InMemory(h) => self.storage.destroy(h), | ||||||
| 			NodeHandle::Hash(h) => { | 			NodeHandle::Hash(h) => { | ||||||
| @ -631,17 +643,18 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 			} | 			} | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		let opt = self.inspect(stored, move |trie, node| trie.remove_inspector(node, partial))?; | 		let opt = self.inspect(stored, move |trie, node| trie.remove_inspector(node, partial, old_val))?; | ||||||
| 
 | 
 | ||||||
| 		Ok(opt.map(|(new, changed)| (self.storage.alloc(new), changed))) | 		Ok(opt.map(|(new, changed)| (self.storage.alloc(new), changed))) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/// the removal inspector
 | 	/// the removal inspector
 | ||||||
| 	fn remove_inspector(&mut self, node: Node, partial: NibbleSlice) -> super::Result<Action> { | 	fn remove_inspector(&mut self, node: Node, partial: NibbleSlice, old_val: &mut Option<DBValue>) -> super::Result<Action> { | ||||||
| 		Ok(match (node, partial.is_empty()) { | 		Ok(match (node, partial.is_empty()) { | ||||||
| 			(Node::Empty, _) => Action::Delete, | 			(Node::Empty, _) => Action::Delete, | ||||||
| 			(Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)), | 			(Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)), | ||||||
| 			(Node::Branch(children, _), true) => { | 			(Node::Branch(children, Some(val)), true) => { | ||||||
|  | 				*old_val = Some(val); | ||||||
| 				// always replace since we took the value out.
 | 				// always replace since we took the value out.
 | ||||||
| 				Action::Replace(self.fix(Node::Branch(children, None))?) | 				Action::Replace(self.fix(Node::Branch(children, None))?) | ||||||
| 			} | 			} | ||||||
| @ -649,7 +662,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 				let idx = partial.at(0) as usize; | 				let idx = partial.at(0) as usize; | ||||||
| 				if let Some(child) = children[idx].take() { | 				if let Some(child) = children[idx].take() { | ||||||
| 					trace!(target: "trie", "removing value out of branch child, partial={:?}", partial); | 					trace!(target: "trie", "removing value out of branch child, partial={:?}", partial); | ||||||
| 					match self.remove_at(child, partial.mid(1))? { | 					match self.remove_at(child, partial.mid(1), old_val)? { | ||||||
| 						Some((new, changed)) => { | 						Some((new, changed)) => { | ||||||
| 							children[idx] = Some(new.into()); | 							children[idx] = Some(new.into()); | ||||||
| 							let branch = Node::Branch(children, value); | 							let branch = Node::Branch(children, value); | ||||||
| @ -675,6 +688,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 			(Node::Leaf(encoded, value), _) => { | 			(Node::Leaf(encoded, value), _) => { | ||||||
| 				if NibbleSlice::from_encoded(&encoded).0 == partial { | 				if NibbleSlice::from_encoded(&encoded).0 == partial { | ||||||
| 					// this is the node we were looking for. Let's delete it.
 | 					// this is the node we were looking for. Let's delete it.
 | ||||||
|  | 					*old_val = Some(value); | ||||||
| 					Action::Delete | 					Action::Delete | ||||||
| 				} else { | 				} else { | ||||||
| 					// leaf the node alone.
 | 					// leaf the node alone.
 | ||||||
| @ -690,7 +704,7 @@ impl<'a> TrieDBMut<'a> { | |||||||
| 				if cp == existing_len { | 				if cp == existing_len { | ||||||
| 					// try to remove from the child branch.
 | 					// try to remove from the child branch.
 | ||||||
| 					trace!(target: "trie", "removing from extension child, partial={:?}", partial); | 					trace!(target: "trie", "removing from extension child, partial={:?}", partial); | ||||||
| 					match self.remove_at(child_branch, partial.mid(cp))? { | 					match self.remove_at(child_branch, partial.mid(cp), old_val)? { | ||||||
| 						Some((new_child, changed)) => { | 						Some((new_child, changed)) => { | ||||||
| 							let new_child = new_child.into(); | 							let new_child = new_child.into(); | ||||||
| 
 | 
 | ||||||
| @ -907,28 +921,35 @@ impl<'a> TrieMut for TrieDBMut<'a> { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<()> { | 	fn insert(&mut self, key: &[u8], value: &[u8]) -> super::Result<Option<DBValue>> { | ||||||
| 		if value.is_empty() { | 		if value.is_empty() { return self.remove(key) } | ||||||
| 			return self.remove(key); | 
 | ||||||
| 		} | 		let mut old_val = None; | ||||||
| 
 | 
 | ||||||
| 		trace!(target: "trie", "insert: key={:?}, value={:?}", key.pretty(), value.pretty()); | 		trace!(target: "trie", "insert: key={:?}, value={:?}", key.pretty(), value.pretty()); | ||||||
| 
 | 
 | ||||||
| 		let root_handle = self.root_handle(); | 		let root_handle = self.root_handle(); | ||||||
| 		let (new_handle, changed) = self.insert_at(root_handle, NibbleSlice::new(key), DBValue::from_slice(value))?; | 		let (new_handle, changed) = self.insert_at( | ||||||
|  | 			root_handle, | ||||||
|  | 			NibbleSlice::new(key), | ||||||
|  | 			DBValue::from_slice(value), | ||||||
|  | 			&mut old_val, | ||||||
|  | 		)?; | ||||||
| 
 | 
 | ||||||
| 		trace!(target: "trie", "insert: altered trie={}", changed); | 		trace!(target: "trie", "insert: altered trie={}", changed); | ||||||
| 		self.root_handle = NodeHandle::InMemory(new_handle); | 		self.root_handle = NodeHandle::InMemory(new_handle); | ||||||
| 
 | 
 | ||||||
| 		Ok(()) | 		Ok(old_val) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn remove(&mut self, key: &[u8]) -> super::Result<()> { | 	fn remove(&mut self, key: &[u8]) -> super::Result<Option<DBValue>> { | ||||||
| 		trace!(target: "trie", "remove: key={:?}", key.pretty()); | 		trace!(target: "trie", "remove: key={:?}", key.pretty()); | ||||||
| 
 | 
 | ||||||
| 		let root_handle = self.root_handle(); | 		let root_handle = self.root_handle(); | ||||||
| 		let key = NibbleSlice::new(key); | 		let key = NibbleSlice::new(key); | ||||||
| 		match self.remove_at(root_handle, key)? { | 		let mut old_val = None; | ||||||
|  | 
 | ||||||
|  | 		match self.remove_at(root_handle, key, &mut old_val)? { | ||||||
| 			Some((handle, changed)) => { | 			Some((handle, changed)) => { | ||||||
| 				trace!(target: "trie", "remove: altered trie={}", changed); | 				trace!(target: "trie", "remove: altered trie={}", changed); | ||||||
| 				self.root_handle = NodeHandle::InMemory(handle); | 				self.root_handle = NodeHandle::InMemory(handle); | ||||||
| @ -938,9 +959,9 @@ impl<'a> TrieMut for TrieDBMut<'a> { | |||||||
| 				self.root_handle = NodeHandle::Hash(SHA3_NULL_RLP); | 				self.root_handle = NodeHandle::Hash(SHA3_NULL_RLP); | ||||||
| 				*self.root = SHA3_NULL_RLP; | 				*self.root = SHA3_NULL_RLP; | ||||||
| 			} | 			} | ||||||
| 		}; | 		} | ||||||
| 
 | 
 | ||||||
| 		Ok(()) | 		Ok(old_val) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1287,4 +1308,29 @@ mod tests { | |||||||
| 		assert!(t.is_empty()); | 		assert!(t.is_empty()); | ||||||
| 		assert_eq!(*t.root(), SHA3_NULL_RLP); | 		assert_eq!(*t.root(), SHA3_NULL_RLP); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	#[test] | ||||||
|  | 	fn return_old_values() { | ||||||
|  | 		let mut seed = H256::new(); | ||||||
|  | 		let x = StandardMap { | ||||||
|  | 				alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), | ||||||
|  | 				min_key: 5, | ||||||
|  | 				journal_key: 0, | ||||||
|  | 				value_mode: ValueMode::Index, | ||||||
|  | 				count: 4, | ||||||
|  | 		}.make_with(&mut seed); | ||||||
|  | 
 | ||||||
|  | 		let mut db = MemoryDB::new(); | ||||||
|  | 		let mut root = H256::new(); | ||||||
|  | 		let mut t = TrieDBMut::new(&mut db, &mut root); | ||||||
|  | 		for &(ref key, ref value) in &x { | ||||||
|  | 			assert!(t.insert(key, value).unwrap().is_none()); | ||||||
|  | 			assert_eq!(t.insert(key, value).unwrap(), Some(DBValue::from_slice(value))); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		for (key, value) in x { | ||||||
|  | 			assert_eq!(t.remove(&key).unwrap(), Some(DBValue::from_slice(&value))); | ||||||
|  | 			assert!(t.remove(&key).unwrap().is_none()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user