|
3 | 3 | //! Serialization support for primitive data types.
|
4 | 4 | #![allow(clippy::float_cmp)]
|
5 | 5 |
|
| 6 | +use std::collections::{HashMap, HashSet, VecDeque}; |
| 7 | +use std::hash::Hash; |
| 8 | + |
6 | 9 | use self::super::{VersionMap, Versionize, VersionizeError, VersionizeResult};
|
7 | 10 | use vmm_sys_util::fam::{FamStruct, FamStructWrapper};
|
8 | 11 |
|
9 | 12 | /// Maximum string len in bytes (16KB).
|
10 | 13 | pub const MAX_STRING_LEN: usize = 16384;
|
11 | 14 | /// Maximum vec size in bytes (10MB).
|
12 | 15 | 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; |
13 | 20 |
|
14 | 21 | /// Implements the Versionize trait for primitive types that also implement
|
15 | 22 | /// serde's Serialize/Deserialize: use serde_bincode as a backend for
|
@@ -333,6 +340,168 @@ where
|
333 | 340 | }
|
334 | 341 | }
|
335 | 342 |
|
| 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 | + |
336 | 505 | // Implement versioning for FAM structures by using the FamStructWrapper interface.
|
337 | 506 | impl<T: Default + FamStruct + Versionize> Versionize for FamStructWrapper<T>
|
338 | 507 | where
|
@@ -697,6 +866,68 @@ mod tests {
|
697 | 866 | assert_eq!(store, restore);
|
698 | 867 | }
|
699 | 868 |
|
| 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 | + |
700 | 931 | #[test]
|
701 | 932 | fn test_ser_de_option() {
|
702 | 933 | let vm = VersionMap::new();
|
@@ -790,6 +1021,62 @@ mod tests {
|
790 | 1021 | );
|
791 | 1022 | }
|
792 | 1023 |
|
| 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 | + |
793 | 1080 | #[test]
|
794 | 1081 | fn test_string_limit() {
|
795 | 1082 | // We need extra 8 bytes for string len.
|
|
0 commit comments