mini-lsm通關筆記-字元相關操作

余为民同志發表於2024-07-07

本文捋一下mini-lsm中的字元相關操作

  • [u8]
  • Vec<u8>
  • Bytes
  • Buf
  • KeySlice
  • KeyBytes

[u8]Vec<u8>

這兩個是rust內建的資料型別。

[u8]: 切片本身並不擁有資料,而是引用了資料。它由一個指向陣列開始處的指標和一個表示陣列長度的計數器組成。[u8]型別通常寫作&[u8],這是因為切片通常是以引用的形式出現的。

Vec<u8>: Vec<u8>是一個可變的、動態大小的向量,它可以儲存任意數量的u8位元組。向量擁有它所儲存的資料,並且可以動態地在其生命週期內增長或縮小。

所以在mini-lsm專案中,解碼的入參一般是&[u8]:

因為用於解碼的資料一般是從檔案中讀出來的不可變的持久化的資料

編碼的入參一般是&mut Vec<u8>或者返回Bytes:

因為在編碼過程中,需要動態的將資料、變數編碼成u8型別寫入Vec

相互轉換:

儘管[u8]Vec<u8>在概念上緊密相關,但它們之間需要進行適當的轉換才能互換使用:

Vec<u8>[u8]:可以透過簡單的引用轉換得到切片,例如:let slice: &[u8] = &vec;

[u8]Vec<u8>:可以透過to_vec()方法將切片轉換為向量,例如:let vector: Vec<u8> = slice.to_vec();

總結來說,Vec<u8>是用於動態操作位元組序列的更通用和靈活的選擇,而[u8]則用於訪問現有位元組序列的非所有者檢視,通常在需要快速訪問而不涉及所有權移動的場景下使用。

Bytes

Rust中,bytes是一個非常流行的第三方庫,用於高效處理位元組序列。這個庫提供了BytesBytesMut型別,它們分別類似於Vec<u8>Vec<u8>的不可變和可變版本,但它們針對位元組序列的常見操作進行了最佳化。

所以在mini-lsm專案中Bytes,常用在可能出現資料共享的情況下。比如MemTable中的map他的keyvalue可能被多個地方獲取。

相互轉換:

BytesVec<u8>:

你可以使用to_vec方法將Bytes轉換為Vec<u8>

use bytes::Bytes;

let b = Bytes::from(vec![1, 2, 3]);
let vec: Vec<u8> = b.to_vec();

當你從Bytes轉換到Vec<u8>時,這通常會涉及到資料的複製,除非你使用一些特殊的技巧或API來避免它。當你呼叫to_vec方法時,Bytes會返回一個包含相同位元組的新Vec<u8>例項。這個操作涉及到資料的複製,因為Vec<u8>需要擁有資料的所有權,而Bytes不能放棄它的所有權,因為它可能正在被其他引用共享。

Vec<u8>Bytes:

你可以使用Bytes::from建構函式或者Into<Bytes>轉換將Vec<u8>轉換為Bytes:

use bytes::Bytes;

let vec = vec![1, 2, 3];
let b: Bytes = Bytes::from(vec);
// 或者
let b: Bytes = vec.into();

當你從Vec<u8>轉換到Bytes時,Bytes會採取資料的所有權,這意味著它會複製資料或共享資料的引用,具體取決於實現細節。在bytes庫的內部,Bytes使用Arc<[u8]>來持有資料,這樣多個Bytes例項可以共享同一個資料緩衝區,從而避免不必要的複製。

當你使用Bytes::from或者Into<Bytes>轉換時,如果底層資料沒有被其他任何引用持有,那麼Bytes可能會簡單地接管Vec<u8>的資料,否則它會建立一個新的Arc來持有資料副本。這是為了保證Bytes例項的不變性,即它是不可變的,並且在多個執行緒間安全共享。

避免複製的情況

在某些情況下,你可以避免顯式的資料複製。例如,如果你有一個Vec<u8>並且想要建立一個Bytes例項,但是你不再需要原來的Vec<u8>,你可以使用Bytes::copy_from_slice方法來避免複製,前提是你能夠保證Vec<u8>的資料不再被引用:

use bytes::Bytes;

let vec = vec![1, 2, 3];
let b = Bytes::copy_from_slice(&vec); // 沒有複製,因為我們只是借用&vec
// 此時,你不能再安全地使用vec,除非你知道它不會被訪問直到b超出作用域

Buf

Buftrait提供了讀取位元組緩衝區的方法。它適用於只讀資料,或者在資料被讀取後不需要保留原始狀態的場景。Buf的主要方法包括:

  • remaining(&self):返回剩餘未讀取的位元組數。
  • chunk(&self):返回一個可讀取的位元組切片。
  • advance(&mut self, cnt: usize):標記已經讀取了cnt個位元組,通常在讀取資料後呼叫,以便更新內部狀態。
  • split(&mut self):從緩衝區中移除已讀取的資料,並返回一個包含這些資料的新Bytes物件。
  • get_u32

同時bytes庫為&[u8]實現了Buf,為&mut [u8]Vec<u8>等實現了BufMut

所以我們對Vec<u8>[u8]型別的資料可以直接使用其定義的函式。

KeySliceKeyBytes

專案的key.rs中的實現,定義了一系列結構體和相關的實現,主要圍繞著處理位元組序列([u8]Vec<u8> 和 ·)的封裝和操作。Key 結構體被設計成一個通用容器,它可以包含不同型別的位元組序列,並提供一系列方法來操作這些資料。

相關文章