Skip to content

Commit f006078

Browse files
author
sicun
committed
add versionize support for more data structs
- add versionize support for VecDequeue/HashMap/HashSet. Signed-off-by: JasonBian <[email protected]>
1 parent 8539966 commit f006078

File tree

4 files changed

+309
-2
lines changed

4 files changed

+309
-2
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v0.1.5
2+
3+
- Add versionize proc macro support for HashMap, HashSet and VecDequeue.
4+
15
# v0.1.4
26

37
- Removed Versionize proc macro support for unions. Serializing unions can lead to undefined behaviour especially when no

coverage_config_x86_64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"coverage_score": 93.2, "exclude_path": "", "crate_features": ""}
1+
{"coverage_score": 93.3, "exclude_path": "", "crate_features": ""}

src/lib.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! The Versionize proc macro supports structures and enums.
1515
//! Supported primitives: u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, char, f32, f64,
1616
//! String, Vec<T>, Arrays up to 32 elements, Box<T>, Wrapping<T>, Option<T>, FamStructWrapper<T>,
17-
//! and (T, U).
17+
//! VecDequeue<T>, HashMap<K, V>, HashSet<T> and (T, U).
1818
//!
1919
//! Known issues and limitations:
2020
//! - Union serialization is not supported via the `Versionize` proc macro.
@@ -54,6 +54,10 @@ pub enum VersionizeError {
5454
StringLength(usize),
5555
/// Vector length exceeded.
5656
VecLength(usize),
57+
/// HashMap length exceeded.
58+
HashMapLength(usize),
59+
/// HashSet length exceeded.
60+
HashSetLength(usize),
5761
}
5862

5963
impl std::fmt::Display for VersionizeError {
@@ -77,6 +81,18 @@ impl std::fmt::Display for VersionizeError {
7781
bad_len,
7882
primitives::MAX_VEC_SIZE
7983
),
84+
HashMapLength(bad_len) => write!(
85+
f,
86+
"HashMap of length {} exceeded maximum size of {} bytes",
87+
bad_len,
88+
primitives::MAX_HASH_MAP_SIZE
89+
),
90+
HashSetLength(bad_len) => write!(
91+
f,
92+
"HashSet of length {} exceeded maximum size of {} bytes",
93+
bad_len,
94+
primitives::MAX_HASH_SET_SIZE
95+
),
8096
}
8197
}
8298
}

src/primitives.rs

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33
//! Serialization support for primitive data types.
44
#![allow(clippy::float_cmp)]
55

6+
use std::collections::{HashMap, HashSet, VecDeque};
7+
use std::hash::Hash;
8+
69
use self::super::{VersionMap, Versionize, VersionizeError, VersionizeResult};
710
use vmm_sys_util::fam::{FamStruct, FamStructWrapper};
811

912
/// Maximum string len in bytes (16KB).
1013
pub const MAX_STRING_LEN: usize = 16384;
1114
/// Maximum vec size in bytes (10MB).
1215
pub const MAX_VEC_SIZE: usize = 10_485_760;
16+
/// Maximum hashmap len in bytes (20MB).
17+
pub const MAX_HASH_MAP_SIZE: usize = 20_971_520;
18+
/// Maximum hashset len in bytes (10MB).
19+
pub const MAX_HASH_SET_SIZE: usize = 10_485_760;
1320

1421
/// Implements the Versionize trait for primitive types that also implement
1522
/// serde's Serialize/Deserialize: use serde_bincode as a backend for
@@ -333,6 +340,168 @@ where
333340
}
334341
}
335342

343+
impl<T> Versionize for VecDeque<T>
344+
where
345+
T: Versionize,
346+
{
347+
#[inline]
348+
fn serialize<W: std::io::Write>(
349+
&self,
350+
mut writer: &mut W,
351+
version_map: &VersionMap,
352+
app_version: u16,
353+
) -> VersionizeResult<()> {
354+
if self.len() > MAX_VEC_SIZE / std::mem::size_of::<T>() {
355+
return Err(VersionizeError::VecLength(self.len()));
356+
}
357+
358+
// Serialize in the same fashion as bincode:
359+
// Write len.
360+
bincode::serialize_into(&mut writer, &self.len())
361+
.map_err(|ref err| VersionizeError::Serialize(format!("{:?}", err)))?;
362+
// Walk the vec and write each element.
363+
for element in self {
364+
element.serialize(writer, version_map, app_version)?;
365+
}
366+
Ok(())
367+
}
368+
369+
#[inline]
370+
fn deserialize<R: std::io::Read>(
371+
mut reader: &mut R,
372+
version_map: &VersionMap,
373+
app_version: u16,
374+
) -> VersionizeResult<Self> {
375+
let mut v = VecDeque::new();
376+
let len: usize = bincode::deserialize_from(&mut reader)
377+
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
378+
379+
if len > MAX_VEC_SIZE / std::mem::size_of::<T>() {
380+
return Err(VersionizeError::VecLength(len));
381+
}
382+
383+
for _ in 0..len {
384+
let element: T = T::deserialize(reader, version_map, app_version)
385+
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
386+
v.push_back(element);
387+
}
388+
Ok(v)
389+
}
390+
391+
// Not used yet.
392+
fn version() -> u16 {
393+
1
394+
}
395+
}
396+
397+
impl<K, V> Versionize for HashMap<K, V>
398+
where
399+
K: Versionize + Eq + Hash + Clone,
400+
V: Versionize + Clone,
401+
{
402+
#[inline]
403+
fn serialize<W: std::io::Write>(
404+
&self,
405+
mut writer: &mut W,
406+
version_map: &VersionMap,
407+
app_version: u16,
408+
) -> VersionizeResult<()> {
409+
if self.len() > MAX_HASH_MAP_SIZE / (std::mem::size_of::<K>() + std::mem::size_of::<V>()) {
410+
return Err(VersionizeError::HashMapLength(self.len()));
411+
}
412+
413+
// Write len
414+
bincode::serialize_into(&mut writer, &self.len())
415+
.map_err(|ref err| VersionizeError::Serialize(format!("{:?}", err)))?;
416+
// Walk the hash map and write each element.
417+
for (k, v) in self.iter() {
418+
(k.clone(), v.clone()).serialize(writer, version_map, app_version)?;
419+
}
420+
Ok(())
421+
}
422+
423+
#[inline]
424+
fn deserialize<R: std::io::Read>(
425+
mut reader: &mut R,
426+
version_map: &VersionMap,
427+
app_version: u16,
428+
) -> VersionizeResult<Self> {
429+
let mut map = HashMap::new();
430+
let len: usize = bincode::deserialize_from(&mut reader)
431+
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
432+
433+
if len > MAX_HASH_MAP_SIZE / (std::mem::size_of::<K>() + std::mem::size_of::<V>()) {
434+
return Err(VersionizeError::HashMapLength(len));
435+
}
436+
437+
for _ in 0..len {
438+
let element: (K, V) = <(K, V)>::deserialize(reader, version_map, app_version)
439+
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
440+
map.insert(element.0, element.1);
441+
}
442+
Ok(map)
443+
}
444+
445+
// Not used yet.
446+
fn version() -> u16 {
447+
1
448+
}
449+
}
450+
451+
impl<T> Versionize for HashSet<T>
452+
where
453+
T: Versionize + Hash + Eq,
454+
{
455+
#[inline]
456+
fn serialize<W: std::io::Write>(
457+
&self,
458+
mut writer: &mut W,
459+
version_map: &VersionMap,
460+
app_version: u16,
461+
) -> VersionizeResult<()> {
462+
if self.len() > MAX_HASH_SET_SIZE / std::mem::size_of::<T>() {
463+
return Err(VersionizeError::HashSetLength(self.len()));
464+
}
465+
466+
// Serialize in the same fashion as bincode:
467+
// Write len.
468+
bincode::serialize_into(&mut writer, &self.len())
469+
.map_err(|ref err| VersionizeError::Serialize(format!("{:?}", err)))?;
470+
// Walk the vec and write each element.
471+
for element in self {
472+
element.serialize(writer, version_map, app_version)?;
473+
}
474+
Ok(())
475+
}
476+
477+
#[inline]
478+
fn deserialize<R: std::io::Read>(
479+
mut reader: &mut R,
480+
version_map: &VersionMap,
481+
app_version: u16,
482+
) -> VersionizeResult<Self> {
483+
let mut set = HashSet::new();
484+
let len: usize = bincode::deserialize_from(&mut reader)
485+
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
486+
487+
if len > MAX_HASH_SET_SIZE / std::mem::size_of::<T>() {
488+
return Err(VersionizeError::HashSetLength(len));
489+
}
490+
491+
for _ in 0..len {
492+
let element: T = T::deserialize(reader, version_map, app_version)
493+
.map_err(|ref err| VersionizeError::Deserialize(format!("{:?}", err)))?;
494+
set.insert(element);
495+
}
496+
Ok(set)
497+
}
498+
499+
// Not used yet.
500+
fn version() -> u16 {
501+
1
502+
}
503+
}
504+
336505
// Implement versioning for FAM structures by using the FamStructWrapper interface.
337506
impl<T: Default + FamStruct + Versionize> Versionize for FamStructWrapper<T>
338507
where
@@ -697,6 +866,68 @@ mod tests {
697866
assert_eq!(store, restore);
698867
}
699868

869+
#[test]
870+
fn test_ser_de_vec_deque() {
871+
let vm = VersionMap::new();
872+
let mut snapshot_mem = vec![0u8; 64];
873+
874+
let mut store = VecDeque::new();
875+
store.push_back("test 1".to_owned());
876+
store.push_back("test 2".to_owned());
877+
store.push_back("test 3".to_owned());
878+
879+
store
880+
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
881+
.unwrap();
882+
let restore =
883+
<Vec<String> as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1).unwrap();
884+
885+
assert_eq!(store, restore);
886+
}
887+
888+
#[test]
889+
fn test_ser_de_hash_map() {
890+
let vm = VersionMap::new();
891+
let mut snapshot_mem = vec![0u8; 128];
892+
893+
let mut store = HashMap::new();
894+
store.insert(1, "test 1".to_owned());
895+
store.insert(2, "test 2".to_owned());
896+
store.insert(3, "test 3".to_owned());
897+
898+
store
899+
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
900+
.unwrap();
901+
let restore = <HashMap<usize, String> as Versionize>::deserialize(
902+
&mut snapshot_mem.as_slice(),
903+
&vm,
904+
1,
905+
)
906+
.unwrap();
907+
908+
assert_eq!(store, restore);
909+
}
910+
911+
#[test]
912+
fn test_ser_de_hash_set() {
913+
let vm = VersionMap::new();
914+
let mut snapshot_mem = vec![0u8; 64];
915+
916+
let mut store = HashSet::new();
917+
store.insert("test 1".to_owned());
918+
store.insert("test 2".to_owned());
919+
store.insert("test 3".to_owned());
920+
921+
store
922+
.serialize(&mut snapshot_mem.as_mut_slice(), &vm, 1)
923+
.unwrap();
924+
let restore =
925+
<HashSet<String> as Versionize>::deserialize(&mut snapshot_mem.as_slice(), &vm, 1)
926+
.unwrap();
927+
928+
assert_eq!(store, restore);
929+
}
930+
700931
#[test]
701932
fn test_ser_de_option() {
702933
let vm = VersionMap::new();
@@ -790,6 +1021,62 @@ mod tests {
7901021
);
7911022
}
7921023

1024+
#[test]
1025+
fn test_vec_deque_limit() {
1026+
// We need extra 8 bytes for vector len.
1027+
let mut snapshot_mem = vec![0u8; MAX_VEC_SIZE + 8];
1028+
let err = VecDeque::from(vec![123u8; MAX_VEC_SIZE + 1])
1029+
.serialize(&mut snapshot_mem.as_mut_slice(), &VersionMap::new(), 1)
1030+
.unwrap_err();
1031+
assert_eq!(err, VersionizeError::VecLength(MAX_VEC_SIZE + 1));
1032+
assert_eq!(
1033+
format!("{}", err),
1034+
"Vec of length 10485761 exceeded maximum size of 10485760 bytes"
1035+
);
1036+
}
1037+
1038+
#[test]
1039+
fn test_hash_map_limit() {
1040+
// We need extra 8 bytes for vector len.
1041+
let mut snapshot_mem = vec![0u8; MAX_HASH_MAP_SIZE / 16 + 1];
1042+
let mut err = HashMap::with_capacity(MAX_HASH_MAP_SIZE / 16 + 1);
1043+
for i in 0..(MAX_HASH_MAP_SIZE / 16 + 1) {
1044+
err.insert(i, i);
1045+
}
1046+
let err = err
1047+
.serialize(&mut snapshot_mem.as_mut_slice(), &VersionMap::new(), 1)
1048+
.unwrap_err();
1049+
assert_eq!(
1050+
err,
1051+
VersionizeError::HashMapLength(MAX_HASH_MAP_SIZE / 16 + 1)
1052+
);
1053+
assert_eq!(
1054+
format!("{}", err),
1055+
"HashMap of length 1310721 exceeded maximum size of 20971520 bytes"
1056+
);
1057+
}
1058+
1059+
#[test]
1060+
fn test_hash_set_limit() {
1061+
// We need extra 8 bytes for vector len.
1062+
let mut snapshot_mem = vec![0u8; MAX_HASH_SET_SIZE / 8 + 1];
1063+
let mut err = HashSet::with_capacity(MAX_HASH_SET_SIZE / 8 + 1);
1064+
for i in 0..(MAX_HASH_SET_SIZE / 8 + 1) {
1065+
err.insert(i);
1066+
}
1067+
let err = err
1068+
.serialize(&mut snapshot_mem.as_mut_slice(), &VersionMap::new(), 1)
1069+
.unwrap_err();
1070+
assert_eq!(
1071+
err,
1072+
VersionizeError::HashSetLength(MAX_HASH_SET_SIZE / 8 + 1)
1073+
);
1074+
assert_eq!(
1075+
format!("{}", err),
1076+
"HashSet of length 1310721 exceeded maximum size of 10485760 bytes"
1077+
);
1078+
}
1079+
7931080
#[test]
7941081
fn test_string_limit() {
7951082
// We need extra 8 bytes for string len.

0 commit comments

Comments
 (0)