1mod free_segments_ledger;
4mod page_ledger;
5mod raw_record;
6mod table_reader;
7mod write_at;
8
9use wasm_dbms_api::prelude::{Encode, MemoryResult, Page, PageOffset};
10
11use self::free_segments_ledger::FreeSegmentsLedger;
12use self::page_ledger::PageLedger;
13use self::raw_record::RawRecord;
14pub use self::table_reader::{NextRecord, TableReader};
15use self::write_at::WriteAt;
16use crate::{MemoryAccess, TableRegistryPage, align_up};
17
18pub struct TableRegistry {
27 free_segments_ledger: FreeSegmentsLedger,
28 pub(crate) page_ledger: PageLedger,
29}
30
31impl TableRegistry {
32 pub fn load(table_pages: TableRegistryPage, mm: &impl MemoryAccess) -> MemoryResult<Self> {
34 Ok(Self {
35 free_segments_ledger: FreeSegmentsLedger::load(table_pages.free_segments_page, mm)?,
36 page_ledger: PageLedger::load(table_pages.pages_list_page, mm)?,
37 })
38 }
39
40 pub fn insert<E>(&mut self, record: E, mm: &mut impl MemoryAccess) -> MemoryResult<()>
44 where
45 E: Encode,
46 {
47 let raw_record = RawRecord::new(record);
49 let write_at = self.get_write_position(&raw_record, mm)?;
50
51 let aligned_offset = align_up::<E>(write_at.offset() as usize) as PageOffset;
53
54 mm.write_at(write_at.page(), aligned_offset, &raw_record)?;
56
57 self.post_write(write_at, &raw_record, mm)
59 }
60
61 pub fn read<'a, E, MA>(&'a self, mm: &'a MA) -> TableReader<'a, E, MA>
65 where
66 E: Encode,
67 MA: MemoryAccess,
68 {
69 TableReader::new(&self.page_ledger, mm)
70 }
71
72 pub fn delete(
76 &mut self,
77 record: impl Encode,
78 page: Page,
79 offset: PageOffset,
80 mm: &mut impl MemoryAccess,
81 ) -> MemoryResult<()> {
82 let raw_record = RawRecord::new(record);
83
84 mm.zero(page, offset, &raw_record)?;
86
87 self.free_segments_ledger
89 .insert_free_segment(page, offset, &raw_record, mm)
90 }
91
92 pub fn update(
99 &mut self,
100 new_record: impl Encode,
101 old_record: impl Encode,
102 old_page: Page,
103 old_offset: PageOffset,
104 mm: &mut impl MemoryAccess,
105 ) -> MemoryResult<()> {
106 if new_record.size() == old_record.size() {
107 self.update_in_place(new_record, old_page, old_offset, mm)
108 } else {
109 self.update_by_realloc(new_record, old_record, old_page, old_offset, mm)
110 }
111 }
112
113 fn update_in_place(
117 &mut self,
118 record: impl Encode,
119 page: Page,
120 offset: PageOffset,
121 mm: &mut impl MemoryAccess,
122 ) -> MemoryResult<()> {
123 let raw_record = RawRecord::new(record);
124 mm.write_at(page, offset, &raw_record)
125 }
126
127 fn update_by_realloc(
131 &mut self,
132 new_record: impl Encode,
133 old_record: impl Encode,
134 old_page: Page,
135 old_offset: PageOffset,
136 mm: &mut impl MemoryAccess,
137 ) -> MemoryResult<()> {
138 self.delete(old_record, old_page, old_offset, mm)?;
140
141 self.insert(new_record, mm)
143 }
144
145 fn get_write_position<E>(
147 &mut self,
148 record: &RawRecord<E>,
149 mm: &mut impl MemoryAccess,
150 ) -> MemoryResult<WriteAt>
151 where
152 E: Encode,
153 {
154 if let Some(segment) = self
156 .free_segments_ledger
157 .find_reusable_segment(record, mm)?
158 {
159 return Ok(WriteAt::ReusedSegment(segment));
160 }
161
162 self.page_ledger
164 .get_page_and_offset_for_record(record, mm)
165 .map(|(page, offset)| WriteAt::End(page, offset))
166 }
167
168 fn post_write<E>(
173 &mut self,
174 write_at: WriteAt,
175 record: &RawRecord<E>,
176 mm: &mut impl MemoryAccess,
177 ) -> MemoryResult<()>
178 where
179 E: Encode,
180 {
181 match write_at {
182 WriteAt::ReusedSegment(free_segment) => {
183 self.free_segments_ledger
185 .commit_reused_space(record, free_segment, mm)
186 }
187 WriteAt::End(page, ..) => {
188 self.page_ledger.commit(page, record, mm)
190 }
191 }
192 }
193}
194
195#[cfg(test)]
197pub(crate) mod test_utils {
198 use wasm_dbms_api::prelude::{
199 DEFAULT_ALIGNMENT, DataSize, DecodeError, Encode, MSize, MemoryError, MemoryResult,
200 PageOffset,
201 };
202
203 #[derive(Debug, Clone, PartialEq, Eq)]
205 pub struct User {
206 pub id: u32,
207 pub name: String,
208 pub email: String,
209 pub age: u32,
210 }
211
212 impl Encode for User {
213 const SIZE: DataSize = DataSize::Dynamic;
214
215 const ALIGNMENT: PageOffset = DEFAULT_ALIGNMENT;
216
217 fn encode(&'_ self) -> std::borrow::Cow<'_, [u8]> {
218 let mut buf = Vec::new();
219 buf.extend_from_slice(&self.id.to_le_bytes());
221 buf.extend_from_slice(&(self.name.len() as u16).to_le_bytes());
223 buf.extend_from_slice(self.name.as_bytes());
224 buf.extend_from_slice(&(self.email.len() as u16).to_le_bytes());
226 buf.extend_from_slice(self.email.as_bytes());
227 buf.extend_from_slice(&self.age.to_le_bytes());
229 std::borrow::Cow::Owned(buf)
230 }
231
232 fn decode(data: std::borrow::Cow<[u8]>) -> MemoryResult<Self>
233 where
234 Self: Sized,
235 {
236 if data.len() < 12 {
237 return Err(MemoryError::DecodeError(DecodeError::TooShort));
238 }
239 let mut offset = 0;
240 let id = u32::from_le_bytes(data[offset..offset + 4].try_into().unwrap());
242 offset += 4;
243 let name_len =
245 u16::from_le_bytes(data[offset..offset + 2].try_into().unwrap()) as usize;
246 offset += 2;
247 let name = String::from_utf8_lossy(&data[offset..offset + name_len]).to_string();
248 offset += name_len;
249 let email_len =
251 u16::from_le_bytes(data[offset..offset + 2].try_into().unwrap()) as usize;
252 offset += 2;
253 let email = String::from_utf8_lossy(&data[offset..offset + email_len]).to_string();
254 offset += email_len;
255 let age = u32::from_le_bytes(data[offset..offset + 4].try_into().unwrap());
257
258 Ok(User {
259 id,
260 name,
261 email,
262 age,
263 })
264 }
265
266 fn size(&self) -> MSize {
267 (4 + 2 + self.name.len() + 2 + self.email.len() + 4) as MSize
268 }
269 }
270}
271
272#[cfg(test)]
273mod tests {
274
275 use self::test_utils::User;
276 use super::free_segments_ledger::FreeSegment;
277 use super::table_reader::NextRecord;
278 use super::*;
279 use crate::{HeapMemoryProvider, MemoryManager};
280
281 #[test]
282 fn test_should_create_table_registry() {
283 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
284 let page_ledger_page = mm.allocate_page().expect("failed to get page");
285 let free_segments_page = mm.allocate_page().expect("failed to get page");
286 let table_pages = TableRegistryPage {
287 pages_list_page: page_ledger_page,
288 free_segments_page,
289 };
290
291 let registry: MemoryResult<TableRegistry> = TableRegistry::load(table_pages, &mm);
292 assert!(registry.is_ok());
293 }
294
295 #[test]
296 fn test_should_get_write_at_end() {
297 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
298 let mut registry = registry(&mut mm);
299
300 let record = RawRecord::new(User {
301 id: 1,
302 name: "Test".to_string(),
303 email: "new_user@example.com".to_string(),
304 age: 25,
305 });
306 let write_at = registry
307 .get_write_position(&record, &mut mm)
308 .expect("failed to get write at");
309
310 assert!(matches!(write_at, WriteAt::End(_, 0)));
311 }
312
313 #[test]
314 fn test_should_get_write_at_free_segment() {
315 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
316 let mut registry = registry(&mut mm);
317
318 let record = RawRecord::new(User {
319 id: 1,
320 name: "Test".to_string(),
321 email: "new_user@example.com".to_string(),
322 age: 25,
323 });
324 let (page, _) = registry
326 .page_ledger
327 .get_page_and_offset_for_record(&record, &mut mm)
328 .expect("failed to get page and offset");
329 registry
330 .page_ledger
331 .commit(page, &record, &mut mm)
332 .expect("failed to commit page ledger");
333 registry
335 .free_segments_ledger
336 .insert_free_segment(page, 256, &record, &mut mm)
337 .expect("failed to insert free segment");
338
339 let write_at = registry
340 .get_write_position(&record, &mut mm)
341 .expect("failed to get write at");
342
343 let reused_segment = match write_at {
344 WriteAt::ReusedSegment(segment) => segment.segment,
345 _ => panic!("expected reused segment"),
346 };
347
348 assert_eq!(
349 reused_segment,
350 FreeSegment {
351 page,
352 offset: 256,
353 size: 64, }
355 );
356 }
357
358 #[test]
359 fn test_should_insert_record_into_table_registry() {
360 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
361 let mut registry = registry(&mut mm);
362
363 let record = User {
364 id: 1,
365 name: "Test".to_string(),
366 email: "new_user@example.com".to_string(),
367 age: 25,
368 };
369
370 assert!(registry.insert(record, &mut mm).is_ok());
372 }
373
374 #[test]
375 fn test_should_manage_to_insert_users_to_exceed_one_page() {
376 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
377 let mut registry = registry(&mut mm);
378
379 for id in 0..4000 {
380 let record = User {
381 id,
382 name: format!("User {}", id),
383 email: "new_user@example.com".to_string(),
384 age: 20 + id,
385 };
386 registry
387 .insert(record, &mut mm)
388 .expect("failed to insert record");
389 }
390 }
391
392 #[test]
393 fn test_should_delete_record() {
394 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
395 let mut registry = registry(&mut mm);
396
397 let record = User {
398 id: 1,
399 name: "Test".to_string(),
400 email: "new_user@example.com".to_string(),
401 age: 25,
402 };
403
404 registry
406 .insert(record.clone(), &mut mm)
407 .expect("failed to insert");
408
409 let mut reader = registry.read(&mm);
411 let next_record: NextRecord<User> = reader
412 .try_next()
413 .expect("failed to read")
414 .expect("no record");
415 let page = next_record.page;
416 let offset = next_record.offset;
417 let record = next_record.record;
418 let raw_user = RawRecord::new(record.clone());
419 let raw_user_size = raw_user.size();
420
421 assert!(registry.delete(record, page, offset, &mut mm).is_ok());
423
424 let mut reader = registry.read::<User, _>(&mm);
426 assert!(reader.try_next().expect("failed to read").is_none());
427
428 let free_segment = registry
430 .free_segments_ledger
431 .find_reusable_segment(
432 &User {
433 id: 2,
434 name: "Test".to_string(),
435 email: "new_user@example.com".to_string(),
436 age: 25,
437 },
438 &mm,
439 )
440 .expect("failed to find free segment")
441 .expect("could not find the free segment after free")
442 .segment;
443 assert_eq!(free_segment.page, page);
444 assert_eq!(free_segment.offset, offset);
445 assert_eq!(free_segment.size, 64); let mut buffer = vec![0u8; raw_user_size as usize];
449 mm.read_at_raw(page, offset, &mut buffer)
450 .expect("failed to read memory");
451 assert!(buffer.iter().all(|&b| b == 0));
452 }
453
454 #[test]
455 fn test_should_update_record_in_place() {
456 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
457 let mut registry = registry(&mut mm);
458
459 let old_record = User {
460 id: 1,
461 name: "John".to_string(),
462 email: "new_user@example.com".to_string(),
463 age: 28,
464 };
465 let new_record = User {
466 id: 1,
467 name: "Mark".to_string(), email: "new_user@example.com".to_string(),
469 age: 30,
470 };
471
472 registry
474 .insert(old_record.clone(), &mut mm)
475 .expect("failed to insert");
476
477 let mut reader = registry.read::<User, _>(&mm);
479 let next_record = reader
480 .try_next()
481 .expect("failed to read")
482 .expect("no record");
483 let page = next_record.page;
484 let offset = next_record.offset;
485
486 assert!(
488 registry
489 .update(
490 new_record.clone(),
491 next_record.record.clone(),
492 page,
493 offset,
494 &mut mm,
495 )
496 .is_ok()
497 );
498
499 let mut reader = registry.read::<User, _>(&mm);
501 let next_record = reader
502 .try_next()
503 .expect("failed to read")
504 .expect("no record");
505 assert_eq!(next_record.page, page); assert_eq!(next_record.offset, offset); assert_eq!(next_record.record, new_record);
508 }
509
510 #[test]
511 fn test_should_update_record_reallocating() {
512 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
513 let mut registry = registry(&mut mm);
514
515 let old_record = User {
516 id: 1,
517 name: "John".to_string(),
518 email: "new_user@example.com".to_string(),
519 age: 28,
520 };
521 let extra_user = User {
523 id: 2,
524 name: "Extra".to_string(),
525 email: "new_user@example.com".to_string(),
526 age: 25,
527 };
528 let new_record = User {
529 id: 1,
530 name: "Alexanderejruwgjowergjioewrgjioewrigjewriogjweoirgjiowerjgoiwerjiogewirogjowejrgiwer".to_string(), email: "new_user@example.com".to_string(),
532 age: 30,
533 };
534
535 registry
537 .insert(old_record.clone(), &mut mm)
538 .expect("failed to insert");
539 registry
541 .insert(extra_user.clone(), &mut mm)
542 .expect("failed to insert extra user");
543
544 let mut reader = registry.read::<User, _>(&mm);
546 let old_record_from_db = reader
547 .try_next()
548 .expect("failed to read")
549 .expect("no record");
550 assert_eq!(old_record_from_db.record, old_record);
551 let page = old_record_from_db.page;
552 let offset = old_record_from_db.offset;
553
554 assert!(
556 registry
557 .update(
558 new_record.clone(),
559 old_record_from_db.record.clone(),
560 page,
561 offset,
562 &mut mm,
563 )
564 .is_ok()
565 );
566
567 let mut reader = registry.read::<User, _>(&mm);
569
570 let _ = reader
572 .try_next()
573 .expect("failed to read")
574 .expect("no record");
575
576 let updated_record = reader
577 .try_next()
578 .expect("failed to read")
579 .expect("no record");
580 assert_ne!(updated_record.offset, offset); assert_eq!(updated_record.record, new_record);
582 }
583
584 #[test]
585 fn test_should_insert_delete_insert_many() {
586 const COUNT: u32 = 1_000;
587 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
588 let mut registry = registry(&mut mm);
589 for id in 0..COUNT {
590 let record = User {
591 id,
592 name: format!("User {id}"),
593 email: format!("user_{id}@example.com"),
594 age: 20,
595 };
596
597 registry
599 .insert(record.clone(), &mut mm)
600 .expect("failed to insert");
601 }
602
603 for id in (0..COUNT).filter(|id| id % 2 == 1) {
605 let record = User {
606 id,
607 name: format!("User {id}"),
608 email: format!("user_{id}@example.com"),
609 age: 20,
610 };
611 let mut reader = registry.read::<User, _>(&mm);
613 let mut deleted = false;
614 while let Some(next_record) = reader.try_next().expect("failed to read") {
615 if next_record.record.id == id {
616 registry
617 .delete(
618 record.clone(),
619 next_record.page,
620 next_record.offset,
621 &mut mm,
622 )
623 .expect("failed to delete");
624 deleted = true;
625 break;
626 }
627 }
628 assert!(deleted, "record with id {} was not found", id);
629 }
630
631 for id in (0..COUNT).filter(|id| id % 2 == 0) {
633 let record = User {
634 id,
635 name: format!("User {id}"),
636 email: format!("user_{id}@example.com"),
637 age: 20,
638 };
639 let mut reader = registry.read::<User, _>(&mm);
641 let mut deleted = false;
642 while let Some(next_record) = reader.try_next().expect("failed to read") {
643 if next_record.record.id == id {
644 registry
645 .delete(
646 record.clone(),
647 next_record.page,
648 next_record.offset,
649 &mut mm,
650 )
651 .expect("failed to delete");
652 deleted = true;
653 break;
654 }
655 }
656 assert!(deleted, "record with id {} was not found", id);
657 }
658
659 for id in 0..COUNT {
661 let record = User {
662 id,
663 name: format!("User {id}"),
664 email: format!("user_{id}@example.com"),
665 age: 20,
666 };
667
668 registry
670 .insert(record.clone(), &mut mm)
671 .expect("failed to insert");
672 }
673 }
674
675 #[test]
676 fn test_should_reduce_free_segment_size_with_padding() {
677 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
678 let mut registry = registry(&mut mm);
679
680 let long_name = vec!['A'; 1024].into_iter().collect::<String>();
682 let record = User {
683 id: 1,
684 name: "Test User".to_string(),
685 email: long_name,
686 age: 30,
687 };
688 registry
689 .insert(record.clone(), &mut mm)
690 .expect("failed to insert");
691 let mut reader = registry.read::<User, _>(&mm);
693 let next_record = reader
694 .try_next()
695 .expect("failed to read")
696 .expect("no record");
697 registry
699 .delete(
700 next_record.record,
701 next_record.page,
702 next_record.offset,
703 &mut mm,
704 )
705 .expect("failed to delete");
706
707 let raw_record = RawRecord::new(record.clone());
709 let free_segment = registry
710 .free_segments_ledger
711 .find_reusable_segment(&raw_record, &mm)
712 .expect("failed to find reusable segment")
713 .expect("could not find the free segment after free")
714 .segment;
715 assert!(free_segment.size >= 1024);
717 let previous_size = free_segment.size;
718
719 let small_record = User {
721 id: 2,
722 name: "Bob The Builder".to_string(),
723 email: "bob@hotmail.com".to_string(),
724 age: 22,
725 };
726 registry
727 .insert(small_record.clone(), &mut mm)
728 .expect("failed to insert small user");
729
730 let free_segment_after = registry
732 .free_segments_ledger
733 .find_reusable_segment(&small_record, &mm)
734 .expect("failed to find reusable segment")
735 .expect("could not find the free segment after inserting small user")
736 .segment;
737
738 assert_eq!(
740 free_segment_after.offset, 64,
741 "expected offset to be 64, but had: {}",
742 free_segment_after.offset
743 ); assert_eq!(
745 free_segment_after.size,
746 previous_size - 64,
747 "Expected free segment to have size: {} but got: {}",
748 previous_size - 64,
749 free_segment_after.size
750 );
751 }
752
753 fn registry(mm: &mut MemoryManager<HeapMemoryProvider>) -> TableRegistry {
754 let page_ledger_page = mm.allocate_page().expect("failed to get page");
755 let free_segments_page = mm.allocate_page().expect("failed to get page");
756 let table_pages = TableRegistryPage {
757 pages_list_page: page_ledger_page,
758 free_segments_page,
759 };
760
761 TableRegistry::load(table_pages, mm).expect("failed to load")
762 }
763}