Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Migrate rlp from ElasticArray to SmallVec #1957

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ parking_lot = "0.2.6"
using_queue = { path = "using_queue" }
table = { path = "table" }
ansi_term = "0.7"
smallvec = "0.2"
# smallvec = { git = "https://github.com/servo/rust-smallvec" }

[features]
default = []
Expand Down
26 changes: 13 additions & 13 deletions util/src/kvdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
//! Key-Value store abstraction with `RocksDB` backend.

use common::*;
use elastic_array::*;
use smallvec::SmallVec;
use std::default::Default;
use rlp::{UntrustedRlp, RlpType, View, Compressible};
use rocksdb::{DB, Writable, WriteBatch, WriteOptions, IteratorMode, DBIterator,
Expand All @@ -34,17 +34,17 @@ pub struct DBTransaction {
enum DBOp {
Insert {
col: Option<u32>,
key: ElasticArray32<u8>,
key: SmallVec<[u8; 32]>,
value: Bytes,
},
InsertCompressed {
col: Option<u32>,
key: ElasticArray32<u8>,
key: SmallVec<[u8; 32]>,
value: Bytes,
},
Delete {
col: Option<u32>,
key: ElasticArray32<u8>,
key: SmallVec<[u8; 32]>,
}
}

Expand All @@ -58,8 +58,8 @@ impl DBTransaction {

/// Insert a key-value pair in the transaction. Any existing value value will be overwritten upon write.
pub fn put(&self, col: Option<u32>, key: &[u8], value: &[u8]) {
let mut ekey = ElasticArray32::new();
ekey.append_slice(key);
let mut ekey = SmallVec::new();
ekey.extend(key.iter().cloned());
self.ops.lock().push(DBOp::Insert {
col: col,
key: ekey,
Expand All @@ -69,8 +69,8 @@ impl DBTransaction {

/// Insert a key-value pair in the transaction. Any existing value value will be overwritten upon write.
pub fn put_vec(&self, col: Option<u32>, key: &[u8], value: Bytes) {
let mut ekey = ElasticArray32::new();
ekey.append_slice(key);
let mut ekey = SmallVec::new();
ekey.extend(key.iter().cloned());
self.ops.lock().push(DBOp::Insert {
col: col,
key: ekey,
Expand All @@ -81,8 +81,8 @@ impl DBTransaction {
/// Insert a key-value pair in the transaction. Any existing value value will be overwritten upon write.
/// Value will be RLP-compressed on flush
pub fn put_compressed(&self, col: Option<u32>, key: &[u8], value: Bytes) {
let mut ekey = ElasticArray32::new();
ekey.append_slice(key);
let mut ekey = SmallVec::new();
ekey.extend(key.iter().cloned());
self.ops.lock().push(DBOp::InsertCompressed {
col: col,
key: ekey,
Expand All @@ -92,8 +92,8 @@ impl DBTransaction {

/// Delete value by key.
pub fn delete(&self, col: Option<u32>, key: &[u8]) {
let mut ekey = ElasticArray32::new();
ekey.append_slice(key);
let mut ekey = SmallVec::new();
ekey.extend(key.iter().cloned());
self.ops.lock().push(DBOp::Delete {
col: col,
key: ekey,
Expand Down Expand Up @@ -194,7 +194,7 @@ pub struct Database {
db: DB,
write_opts: WriteOptions,
cfs: Vec<Column>,
overlay: RwLock<Vec<HashMap<ElasticArray32<u8>, KeyState>>>,
overlay: RwLock<Vec<HashMap<SmallVec<[u8; 32]>, KeyState>>>,
}

impl Database {
Expand Down
1 change: 1 addition & 0 deletions util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ extern crate parking_lot;
pub extern crate using_queue;
pub extern crate table;
extern crate ansi_term;
extern crate smallvec;

pub mod bloom;
pub mod standard;
Expand Down
51 changes: 7 additions & 44 deletions util/src/rlp/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,7 @@ use std::cmp::Ordering;
use std::error::Error as StdError;
use bigint::uint::{Uint, U128, U256};
use hash::{H64, H128, H160, H256, H512, H520, H2048};
use elastic_array::*;

/// Vector like object
pub trait VecLike<T> {
/// Add an element to the collection
fn vec_push(&mut self, value: T);

/// Add a slice to the collection
fn vec_extend(&mut self, slice: &[T]);
}

impl<T> VecLike<T> for Vec<T> where T: Copy {
fn vec_push(&mut self, value: T) {
Vec::<T>::push(self, value)
}

fn vec_extend(&mut self, slice: &[T]) {
Vec::<T>::extend_from_slice(self, slice)
}
}

macro_rules! impl_veclike_for_elastic_array {
($from: ident) => {
impl<T> VecLike<T> for $from<T> where T: Copy {
fn vec_push(&mut self, value: T) {
$from::<T>::push(self, value)
}
fn vec_extend(&mut self, slice: &[T]) {
$from::<T>::append_slice(self, slice)

}
}
}
}

impl_veclike_for_elastic_array!(ElasticArray16);
impl_veclike_for_elastic_array!(ElasticArray32);
impl_veclike_for_elastic_array!(ElasticArray1024);
use smallvec::VecLike;

/// Converts given type to its shortest representation in bytes
///
Expand All @@ -74,7 +37,7 @@ pub trait ToBytes {

impl <'a> ToBytes for &'a str {
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
out.vec_extend(self.as_bytes());
out.extend(self.as_bytes().iter().cloned());
}

fn to_bytes_len(&self) -> usize {
Expand All @@ -84,7 +47,7 @@ impl <'a> ToBytes for &'a str {

impl ToBytes for String {
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
out.vec_extend(self.as_bytes());
out.extend(self.as_bytes().iter().cloned());
}

fn to_bytes_len(&self) -> usize {
Expand All @@ -97,7 +60,7 @@ impl ToBytes for u64 {
let count = self.to_bytes_len();
for i in 0..count {
let j = count - 1 - i;
out.vec_push((*self >> (j * 8)) as u8);
out.push((*self >> (j * 8)) as u8);
}
}

Expand All @@ -106,7 +69,7 @@ impl ToBytes for u64 {

impl ToBytes for bool {
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
out.vec_push(if *self { 1u8 } else { 0u8 })
out.push(if *self { 1u8 } else { 0u8 })
}

fn to_bytes_len(&self) -> usize { 1 }
Expand Down Expand Up @@ -135,7 +98,7 @@ macro_rules! impl_uint_to_bytes {
let count = self.to_bytes_len();
for i in 0..count {
let j = count - 1 - i;
out.vec_push(self.byte(j));
out.push(self.byte(j));
}
}
fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 }
Expand All @@ -150,7 +113,7 @@ macro_rules! impl_hash_to_bytes {
($name: ident) => {
impl ToBytes for $name {
fn to_bytes<V: VecLike<u8>>(&self, out: &mut V) {
out.vec_extend(&self);
out.extend(self.iter().cloned());
}
fn to_bytes_len(&self) -> usize { self.len() }
}
Expand Down
4 changes: 2 additions & 2 deletions util/src/rlp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, P
pub use self::rlpin::{Rlp, RlpIterator};
pub use self::rlpstream::RlpStream;
pub use self::rlpcompression::RlpType;
pub use elastic_array::ElasticArray1024;
pub use smallvec::SmallVec;
use super::hash::H256;

/// The RLP encoded empty data (used to mean "null value").
Expand Down Expand Up @@ -105,7 +105,7 @@ pub fn decode<T>(bytes: &[u8]) -> T where T: RlpDecodable {
/// assert_eq!(out, vec![0x83, b'c', b'a', b't']);
/// }
/// ```
pub fn encode<E>(object: &E) -> ElasticArray1024<u8> where E: RlpEncodable {
pub fn encode<E>(object: &E) -> SmallVec<[u8; 1024]> where E: RlpEncodable {
let mut stream = RlpStream::new();
stream.append(object);
stream.drain()
Expand Down
41 changes: 21 additions & 20 deletions util/src/rlp/rlpcompression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

use rlp::{UntrustedRlp, View, Compressible, encode, ElasticArray1024, Stream, RlpStream};
use rlp::{UntrustedRlp, View, Compressible, encode, Stream, RlpStream};
use rlp::commonrlps::{BLOCKS_RLP_SWAPPER, SNAPSHOT_RLP_SWAPPER};
use smallvec::SmallVec;
use std::collections::HashMap;

/// Stores RLPs used for compression
Expand Down Expand Up @@ -59,14 +60,14 @@ pub enum RlpType {
Snapshot,
}

fn to_elastic(slice: &[u8]) -> ElasticArray1024<u8> {
let mut out = ElasticArray1024::new();
out.append_slice(slice);
fn to_small_vec(slice: &[u8]) -> SmallVec<[u8; 1024]> {
let mut out = SmallVec::new();
out.extend(slice.iter().cloned());
out
}

fn map_rlp<F>(rlp: &UntrustedRlp, f: F) -> Option<ElasticArray1024<u8>> where
F: Fn(&UntrustedRlp) -> Option<ElasticArray1024<u8>> {
fn map_rlp<F>(rlp: &UntrustedRlp, f: F) -> Option<SmallVec<[u8; 1024]>> where
F: Fn(&UntrustedRlp) -> Option<SmallVec<[u8; 1024]>> {
match rlp.iter()
.fold((false, RlpStream::new_list(rlp.item_count())),
|(is_some, mut acc), subrlp| {
Expand All @@ -84,28 +85,28 @@ fn map_rlp<F>(rlp: &UntrustedRlp, f: F) -> Option<ElasticArray1024<u8>> where
}

/// Replace common RLPs with invalid shorter ones.
fn simple_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> ElasticArray1024<u8> {
fn simple_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> SmallVec<[u8; 1024]> {
if rlp.is_data() {
to_elastic(swapper.get_invalid(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw()))
to_small_vec(swapper.get_invalid(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw()))
} else {
map_rlp(rlp, |r| Some(simple_compress(r, swapper))).unwrap_or_else(|| to_elastic(rlp.as_raw()))
map_rlp(rlp, |r| Some(simple_compress(r, swapper))).unwrap_or_else(|| to_small_vec(rlp.as_raw()))
}
}

/// Recover valid RLP from a compressed form.
fn simple_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> ElasticArray1024<u8> {
fn simple_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> SmallVec<[u8; 1024]> {
if rlp.is_data() {
to_elastic(swapper.get_valid(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw()))
to_small_vec(swapper.get_valid(rlp.as_raw()).unwrap_or_else(|| rlp.as_raw()))
} else {
map_rlp(rlp, |r| Some(simple_decompress(r, swapper))).unwrap_or_else(|| to_elastic(rlp.as_raw()))
map_rlp(rlp, |r| Some(simple_decompress(r, swapper))).unwrap_or_else(|| to_small_vec(rlp.as_raw()))
}
}

/// Replace common RLPs with invalid shorter ones, None if no compression achieved.
/// Tries to compress data insides.
fn deep_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<ElasticArray1024<u8>> {
fn deep_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<SmallVec<[u8; 1024]>> {
let simple_swap = ||
swapper.get_invalid(rlp.as_raw()).map(to_elastic);
swapper.get_invalid(rlp.as_raw()).map(to_small_vec);
if rlp.is_data() {
// Try to treat the inside as RLP.
return match rlp.payload_info() {
Expand All @@ -132,9 +133,9 @@ fn deep_compress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<Elas

/// Recover valid RLP from a compressed form, None if no decompression achieved.
/// Tries to decompress compressed data insides.
fn deep_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<ElasticArray1024<u8>> {
fn deep_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<SmallVec<[u8; 1024]>> {
let simple_swap = ||
swapper.get_valid(rlp.as_raw()).map(to_elastic);
swapper.get_valid(rlp.as_raw()).map(to_small_vec);
// Simply decompress data.
if rlp.is_data() { return simple_swap(); }
match rlp.item_count() {
Expand All @@ -152,17 +153,17 @@ fn deep_decompress(rlp: &UntrustedRlp, swapper: &InvalidRlpSwapper) -> Option<El
impl<'a> Compressible for UntrustedRlp<'a> {
type DataType = RlpType;

fn compress(&self, t: RlpType) -> ElasticArray1024<u8> {
fn compress(&self, t: RlpType) -> SmallVec<[u8; 1024]> {
match t {
RlpType::Snapshot => simple_compress(self, &SNAPSHOT_RLP_SWAPPER),
RlpType::Blocks => deep_compress(self, &BLOCKS_RLP_SWAPPER).unwrap_or_else(|| to_elastic(self.as_raw())),
RlpType::Blocks => deep_compress(self, &BLOCKS_RLP_SWAPPER).unwrap_or_else(|| to_small_vec(self.as_raw())),
}
}

fn decompress(&self, t: RlpType) -> ElasticArray1024<u8> {
fn decompress(&self, t: RlpType) -> SmallVec<[u8; 1024]> {
match t {
RlpType::Snapshot => simple_decompress(self, &SNAPSHOT_RLP_SWAPPER),
RlpType::Blocks => deep_decompress(self, &BLOCKS_RLP_SWAPPER).unwrap_or_else(|| to_elastic(self.as_raw())),
RlpType::Blocks => deep_decompress(self, &BLOCKS_RLP_SWAPPER).unwrap_or_else(|| to_small_vec(self.as_raw())),
}
}
}
Expand Down
Loading