1mod block;
19
20use std::collections::HashSet;
21use std::fmt::{Debug, Formatter};
22use std::ops::{BitXor, Bound, Range};
23
24pub use block::*;
25mod block_iterator;
26pub use block_iterator::*;
27mod xor_filter;
28use serde::{Deserialize, Serialize};
29pub use xor_filter::{
30 BlockedXor8FilterBuilder, BlockedXor16FilterBuilder, Xor8FilterBuilder, Xor16FilterBuilder,
31 XorFilterReader,
32};
33pub mod builder;
34pub use builder::*;
35pub mod writer;
36use risingwave_common::catalog::TableId;
37pub use writer::*;
38mod forward_sstable_iterator;
39pub mod multi_builder;
40use bytes::{Buf, BufMut};
41pub use forward_sstable_iterator::*;
42use tracing::warn;
43mod backward_sstable_iterator;
44pub use backward_sstable_iterator::*;
45use risingwave_hummock_sdk::key::{FullKey, KeyPayloadType, UserKey, UserKeyRangeRef};
46use risingwave_hummock_sdk::{HummockEpoch, HummockSstableObjectId};
47
48mod filter;
49mod utils;
50
51pub use filter::{
52 DEFAULT_FILTER_HASH_PREALLOC_KEY_COUNT_CAP, FilterBuilder, FilterBuilderOptions,
53 NoneFilterBuilder,
54};
55pub use utils::{CompressionAlgorithm, xxhash64_checksum, xxhash64_verify};
56use utils::{get_length_prefixed_slice, put_length_prefixed_slice};
57use xxhash_rust::xxh64;
58
59use super::{HummockError, HummockResult};
60use crate::hummock::CachePolicy;
61use crate::store::ReadOptions;
62
63const MAGIC: u32 = 0x5785ab73;
64const OLD_VERSION: u32 = 1;
65const VERSION: u32 = 2;
66
67#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
81pub struct MonotonicDeleteEvent {
82 pub event_key:
83 risingwave_hummock_sdk::key::range_delete_backward_compatibility_serde_struct::PointRange,
84 pub new_epoch: HummockEpoch,
85}
86
87impl MonotonicDeleteEvent {
88 pub fn encode(&self, mut buf: impl BufMut) {
89 self.event_key
90 .left_user_key
91 .encode_length_prefixed(&mut buf);
92 buf.put_u8(if self.event_key.is_exclude_left_key {
93 1
94 } else {
95 0
96 });
97 buf.put_u64_le(self.new_epoch);
98 }
99
100 pub fn decode(buf: &mut &[u8]) -> Self {
101 use risingwave_hummock_sdk::key::range_delete_backward_compatibility_serde_struct::*;
102 let user_key = UserKey::decode_length_prefixed(buf);
103 let exclude_left_key_flag = buf.get_u8();
104 let is_exclude_left_key = match exclude_left_key_flag {
105 0 => false,
106 1 => true,
107 _ => panic!("exclusive flag should be either 0 or 1"),
108 };
109 let new_epoch = buf.get_u64_le();
110 Self {
111 event_key: PointRange {
112 left_user_key: user_key,
113 is_exclude_left_key,
114 },
115 new_epoch,
116 }
117 }
118}
119
120#[derive(Serialize, Deserialize)]
121struct SerdeSstable {
122 id: HummockSstableObjectId,
123 meta: SstableMeta,
124}
125
126impl From<SerdeSstable> for Sstable {
127 fn from(SerdeSstable { id, meta }: SerdeSstable) -> Self {
128 Sstable::new(id, meta, false)
131 }
132}
133
134#[derive(Clone, Deserialize)]
136#[serde(from = "SerdeSstable")]
137pub struct Sstable {
138 pub id: HummockSstableObjectId,
139 pub meta: SstableMeta,
140 #[serde(skip)]
141 pub filter_reader: XorFilterReader,
142 #[serde(skip)]
146 skip_bloom_filter_in_serde: bool,
147}
148
149impl Serialize for Sstable {
150 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
151 where
152 S: serde::Serializer,
153 {
154 let mut serde_sstable = SerdeSstable {
155 id: self.id,
156 meta: self.meta.clone(),
157 };
158 if !self.skip_bloom_filter_in_serde {
159 serde_sstable.meta.bloom_filter = self.filter_reader.encode_to_bytes();
160 }
161 serde_sstable.serialize(serializer)
162 }
163}
164
165impl Debug for Sstable {
166 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
167 f.debug_struct("Sstable")
168 .field("id", &self.id)
169 .field("meta", &self.meta)
170 .finish()
171 }
172}
173
174impl Sstable {
175 pub fn new(
176 id: HummockSstableObjectId,
177 mut meta: SstableMeta,
178 skip_bloom_filter_in_serde: bool,
179 ) -> Self {
180 let filter_data = std::mem::take(&mut meta.bloom_filter);
181 let filter_reader = XorFilterReader::new(&filter_data, &meta.block_metas);
182 Self {
183 id,
184 meta,
185 filter_reader,
186 skip_bloom_filter_in_serde,
187 }
188 }
189
190 #[inline(always)]
191 pub fn has_filter(&self) -> bool {
192 !self.filter_reader.is_empty()
193 }
194
195 pub fn calculate_block_info(&self, block_index: usize) -> (Range<usize>, usize) {
196 let block_meta = &self.meta.block_metas[block_index];
197 let range =
198 block_meta.offset as usize..block_meta.offset as usize + block_meta.len as usize;
199 let uncompressed_capacity = block_meta.uncompressed_size as usize;
200 (range, uncompressed_capacity)
201 }
202
203 #[inline(always)]
204 pub fn hash_for_filter(dist_key: &[u8], table_id: u32) -> u64 {
205 let dist_key_hash = xxh64::xxh64(dist_key, 0);
206 (table_id as u64).bitxor(dist_key_hash)
208 }
209
210 #[inline(always)]
211 pub fn may_match_hash(&self, user_key_range: &UserKeyRangeRef<'_>, hash: u64) -> bool {
212 self.filter_reader
213 .may_match(&self.meta.block_metas, user_key_range, hash)
214 }
215
216 #[inline(always)]
217 pub fn block_count(&self) -> usize {
218 self.meta.block_metas.len()
219 }
220
221 #[inline(always)]
222 pub fn estimated_meta_cache_memory_weight(&self) -> usize {
223 std::mem::size_of::<Self>()
226 + self.meta.estimated_heap_size()
227 + self.filter_reader.estimated_heap_size()
228 }
229}
230
231#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
232pub struct BlockMeta {
233 pub smallest_key: Vec<u8>,
234 pub offset: u32,
235 pub len: u32,
236 pub uncompressed_size: u32,
237 pub total_key_count: u32,
238 pub stale_key_count: u32,
239}
240
241impl BlockMeta {
242 pub fn encode(&self, mut buf: impl BufMut) {
248 buf.put_u32_le(self.offset);
249 buf.put_u32_le(self.len);
250 buf.put_u32_le(self.uncompressed_size);
251 buf.put_u32_le(self.total_key_count);
252 buf.put_u32_le(self.stale_key_count);
253 put_length_prefixed_slice(buf, &self.smallest_key);
254 }
255
256 pub fn decode(buf: &mut &[u8]) -> Self {
257 let offset = buf.get_u32_le();
258 let len = buf.get_u32_le();
259 let uncompressed_size = buf.get_u32_le();
260
261 let total_key_count = buf.get_u32_le();
262 let stale_key_count = buf.get_u32_le();
263 let smallest_key = get_length_prefixed_slice(buf);
264 Self {
265 smallest_key,
266 offset,
267 len,
268 uncompressed_size,
269 total_key_count,
270 stale_key_count,
271 }
272 }
273
274 pub fn decode_from_v1(buf: &mut &[u8]) -> Self {
275 let offset = buf.get_u32_le();
276 let len = buf.get_u32_le();
277 let uncompressed_size = buf.get_u32_le();
278 let total_key_count = 0;
279 let stale_key_count = 0;
280 let smallest_key = get_length_prefixed_slice(buf);
281 Self {
282 smallest_key,
283 offset,
284 len,
285 uncompressed_size,
286 total_key_count,
287 stale_key_count,
288 }
289 }
290
291 #[inline]
292 pub fn encoded_size(&self) -> usize {
293 24 + self.smallest_key.len()
294 }
295
296 pub fn table_id(&self) -> TableId {
297 FullKey::decode(&self.smallest_key).user_key.table_id
298 }
299
300 fn estimated_heap_size(&self) -> usize {
301 self.smallest_key.capacity()
302 }
303}
304
305#[derive(Default, Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
306pub struct SstableMeta {
307 pub block_metas: Vec<BlockMeta>,
308 pub bloom_filter: Vec<u8>,
309 pub estimated_size: u32,
310 pub key_count: u32,
311 pub smallest_key: Vec<u8>,
312 pub largest_key: Vec<u8>,
313 pub meta_offset: u64,
314 #[deprecated]
328 pub monotonic_tombstone_events: Vec<MonotonicDeleteEvent>,
329 pub version: u32,
331}
332
333impl SstableMeta {
334 pub fn encode_to_bytes(&self) -> Vec<u8> {
349 let encoded_size = self.encoded_size();
350 let mut buf = Vec::with_capacity(encoded_size);
351 self.encode_to(&mut buf);
352 buf
353 }
354
355 pub fn encode_to(&self, mut buf: impl BufMut + AsRef<[u8]>) {
356 let start = buf.as_ref().len();
357
358 buf.put_u32_le(
359 utils::checked_into_u32(self.block_metas.len()).unwrap_or_else(|_| {
360 let tmp_full_key = FullKey::decode(&self.smallest_key);
361 panic!(
362 "WARN overflow can't convert block_metas_len {} into u32 table {}",
363 self.block_metas.len(),
364 tmp_full_key.user_key.table_id,
365 )
366 }),
367 );
368 for block_meta in &self.block_metas {
369 block_meta.encode(&mut buf);
370 }
371 put_length_prefixed_slice(&mut buf, &self.bloom_filter);
372 buf.put_u32_le(self.estimated_size);
373 buf.put_u32_le(self.key_count);
374 put_length_prefixed_slice(&mut buf, &self.smallest_key);
375 put_length_prefixed_slice(&mut buf, &self.largest_key);
376 #[expect(deprecated)]
377 buf.put_u32_le(
378 utils::checked_into_u32(self.monotonic_tombstone_events.len()).unwrap_or_else(|_| {
379 let tmp_full_key = FullKey::decode(&self.smallest_key);
380 panic!(
381 "WARN overflow can't convert monotonic_tombstone_events_len {} into u32 table {}",
382 self.monotonic_tombstone_events.len(),
383 tmp_full_key.user_key.table_id,
384 )
385 }),
386 );
387 #[expect(deprecated)]
388 for monotonic_tombstone_event in &self.monotonic_tombstone_events {
389 monotonic_tombstone_event.encode(&mut buf);
390 }
391 buf.put_u64_le(self.meta_offset);
392
393 let end = buf.as_ref().len();
394
395 let checksum = xxhash64_checksum(&buf.as_ref()[start..end]);
396 buf.put_u64_le(checksum);
397 buf.put_u32_le(VERSION);
398 buf.put_u32_le(MAGIC);
399 }
400
401 pub fn decode(buf: &[u8]) -> HummockResult<Self> {
402 let mut cursor = buf.len();
403
404 cursor -= 4;
405 let magic = (&buf[cursor..]).get_u32_le();
406 if magic != MAGIC {
407 return Err(HummockError::magic_mismatch(MAGIC, magic));
408 }
409
410 cursor -= 4;
411 let version = (&buf[cursor..cursor + 4]).get_u32_le();
412 if version != VERSION && version != OLD_VERSION {
413 return Err(HummockError::invalid_format_version(version));
414 }
415
416 cursor -= 8;
417 let checksum = (&buf[cursor..cursor + 8]).get_u64_le();
418 let buf = &mut &buf[..cursor];
419 xxhash64_verify(buf, checksum)?;
420
421 let block_meta_count = buf.get_u32_le() as usize;
422 let mut block_metas = Vec::with_capacity(block_meta_count);
423 if version == OLD_VERSION {
424 for _ in 0..block_meta_count {
425 block_metas.push(BlockMeta::decode_from_v1(buf));
426 }
427 } else {
428 for _ in 0..block_meta_count {
429 block_metas.push(BlockMeta::decode(buf));
430 }
431 }
432
433 let bloom_filter = get_length_prefixed_slice(buf);
434 let estimated_size = buf.get_u32_le();
435 let key_count = buf.get_u32_le();
436 let smallest_key = get_length_prefixed_slice(buf);
437 let largest_key = get_length_prefixed_slice(buf);
438 let tomb_event_count = buf.get_u32_le() as usize;
439 let mut monotonic_tombstone_events = Vec::with_capacity(tomb_event_count);
440 for _ in 0..tomb_event_count {
441 let monotonic_tombstone_event = MonotonicDeleteEvent::decode(buf);
442 monotonic_tombstone_events.push(monotonic_tombstone_event);
443 }
444 let meta_offset = buf.get_u64_le();
445
446 if !monotonic_tombstone_events.is_empty() {
447 warn!(
448 count = monotonic_tombstone_events.len(),
449 tables = ?monotonic_tombstone_events
450 .iter()
451 .map(|event| event.event_key.left_user_key.table_id)
452 .collect::<HashSet<_>>(),
453 "read non-empty range tombstones");
454 }
455
456 #[expect(deprecated)]
457 Ok(Self {
458 block_metas,
459 bloom_filter,
460 estimated_size,
461 key_count,
462 smallest_key,
463 largest_key,
464 meta_offset,
465 monotonic_tombstone_events,
466 version,
467 })
468 }
469
470 #[inline]
471 pub fn encoded_size(&self) -> usize {
472 4 + self
474 .block_metas
475 .iter()
476 .map(|block_meta| block_meta.encoded_size())
477 .sum::<usize>()
478 + 4 + 4 + self.bloom_filter.len()
481 + 4 + 4 + 4 + self.smallest_key.len()
485 + 4 + self.largest_key.len()
487 + 8 + 8 + 4 + 4 }
492
493 #[expect(
494 deprecated,
495 reason = "monotonic_tombstone_events is deprecated but still contributes to decoded meta heap size"
496 )]
497 fn estimated_heap_size(&self) -> usize {
498 self.block_metas.capacity() * std::mem::size_of::<BlockMeta>()
499 + self
500 .block_metas
501 .iter()
502 .map(BlockMeta::estimated_heap_size)
503 .sum::<usize>()
504 + self.bloom_filter.capacity()
505 + self.smallest_key.capacity()
506 + self.largest_key.capacity()
507 + self.monotonic_tombstone_events.capacity()
508 * std::mem::size_of::<MonotonicDeleteEvent>()
509 }
510}
511
512#[derive(Default)]
513pub struct SstableIteratorReadOptions {
514 pub cache_policy: CachePolicy,
515 pub must_iterated_end_user_key: Option<Bound<UserKey<KeyPayloadType>>>,
516 pub max_preload_retry_times: usize,
517 pub prefetch_for_large_query: bool,
518}
519
520impl SstableIteratorReadOptions {
521 pub fn from_read_options(read_options: &ReadOptions) -> Self {
522 Self {
523 cache_policy: read_options.cache_policy,
524 must_iterated_end_user_key: None,
525 max_preload_retry_times: 0,
526 prefetch_for_large_query: read_options.prefetch_options.for_large_query,
527 }
528 }
529}
530
531#[cfg(test)]
532mod tests {
533 use super::*;
534 use crate::hummock::HummockValue;
535 use crate::hummock::iterator::test_utils::{
536 default_builder_opt_for_test, iterator_test_key_of,
537 };
538 use crate::hummock::test_utils::gen_test_sstable_data;
539
540 #[test]
541 fn test_sstable_meta_enc_dec() {
542 #[expect(deprecated)]
543 let meta = SstableMeta {
544 block_metas: vec![
545 BlockMeta {
546 smallest_key: b"0-smallest-key".to_vec(),
547 len: 100,
548 ..Default::default()
549 },
550 BlockMeta {
551 smallest_key: b"5-some-key".to_vec(),
552 offset: 100,
553 len: 100,
554 ..Default::default()
555 },
556 ],
557 bloom_filter: b"0123456789".to_vec(),
558 estimated_size: 123,
559 key_count: 123,
560 smallest_key: b"0-smallest-key".to_vec(),
561 largest_key: b"9-largest-key".to_vec(),
562 meta_offset: 123,
563 monotonic_tombstone_events: vec![],
564 version: VERSION,
565 };
566 let sz = meta.encoded_size();
567 let buf = meta.encode_to_bytes();
568 assert_eq!(sz, buf.len());
569 let decoded_meta = SstableMeta::decode(&buf[..]).unwrap();
570 assert_eq!(decoded_meta, meta);
571
572 println!("buf: {}", buf.len());
573 }
574
575 #[tokio::test]
576 async fn test_sstable_serde() {
577 let (_, meta) = gen_test_sstable_data(
578 default_builder_opt_for_test(),
579 (0..100).clone().map(|x| {
580 (
581 iterator_test_key_of(x),
582 HummockValue::put(format!("overlapped_new_{}", x).as_bytes().to_vec()),
583 )
584 }),
585 )
586 .await;
587
588 let sstable = Sstable::new(42.into(), meta.clone(), true);
590
591 let buffer = bincode::serialize(&sstable).unwrap();
592
593 let s: Sstable = bincode::deserialize(&buffer).unwrap();
594
595 assert_eq!(s.id, sstable.id);
596 assert_eq!(s.meta, sstable.meta);
597 assert!(!sstable.filter_reader.is_empty());
598 assert!(s.filter_reader.is_empty());
600
601 let sstable = Sstable::new(42.into(), meta, false);
603
604 let buffer = bincode::serialize(&sstable).unwrap();
605
606 let s: Sstable = bincode::deserialize(&buffer).unwrap();
607
608 assert_eq!(s.id, sstable.id);
609 assert_eq!(s.meta, sstable.meta);
610 assert_eq!(
611 s.filter_reader.encode_to_bytes(),
612 sstable.filter_reader.encode_to_bytes()
613 );
614 }
615}