1mod autoincrement_ledger;
4mod free_segments_ledger;
5mod index_ledger;
6mod page_ledger;
7mod raw_record;
8mod raw_table_reader;
9mod record_address;
10mod schema_snapshot_ledger;
11mod table_reader;
12mod write_at;
13
14use wasm_dbms_api::prelude::{Encode, MSize, MemoryResult, PageOffset, Value};
15
16pub use self::autoincrement_ledger::AutoincrementLedger;
17use self::free_segments_ledger::FreeSegmentsLedger;
18pub use self::index_ledger::{IndexLedger, IndexTreeWalker};
19use self::page_ledger::PageLedger;
20use self::raw_record::RawRecord;
21pub use self::raw_table_reader::{RawRecordBytes, RawTableReader};
22pub use self::record_address::RecordAddress;
23pub use self::schema_snapshot_ledger::SchemaSnapshotLedger;
24pub use self::table_reader::{NextRecord, TableReader};
25use self::write_at::WriteAt;
26use crate::{MemoryAccess, TableRegistryPage, align_up};
27
28pub struct TableRegistry {
37 schema_snapshot_ledger: SchemaSnapshotLedger,
38 pub(crate) page_ledger: PageLedger,
39 free_segments_ledger: FreeSegmentsLedger,
40 index_ledger: IndexLedger,
41 auto_increment_ledger: Option<AutoincrementLedger>,
42}
43
44impl TableRegistry {
45 pub fn load(table_pages: TableRegistryPage, mm: &mut impl MemoryAccess) -> MemoryResult<Self> {
47 Ok(Self {
48 schema_snapshot_ledger: SchemaSnapshotLedger::load(
49 table_pages.schema_snapshot_page,
50 mm,
51 )?,
52 page_ledger: PageLedger::load(table_pages.pages_list_page, mm)?,
53 free_segments_ledger: FreeSegmentsLedger::load(table_pages.free_segments_page, mm)?,
54 index_ledger: IndexLedger::load(table_pages.index_registry_page, mm)?,
55 auto_increment_ledger: if let Some(page) = table_pages.autoincrement_registry_page {
56 Some(AutoincrementLedger::load(page, mm)?)
57 } else {
58 None
59 },
60 })
61 }
62
63 pub fn insert<E>(
69 &mut self,
70 record: E,
71 mm: &mut impl MemoryAccess,
72 ) -> MemoryResult<RecordAddress>
73 where
74 E: Encode,
75 {
76 let raw_record = RawRecord::new(record);
78 let write_at = self.get_write_position(&raw_record, mm)?;
79
80 let aligned_offset = align_up::<RawRecord<E>>(write_at.offset() as usize) as PageOffset;
82
83 mm.write_at(write_at.page(), aligned_offset, &raw_record)?;
85
86 let pointer = RecordAddress {
87 page: write_at.page(),
88 offset: aligned_offset,
89 };
90
91 self.post_write(write_at, &raw_record, mm)?;
93
94 Ok(pointer)
95 }
96
97 pub fn read<'a, E, MA>(&'a self, mm: &'a mut MA) -> TableReader<'a, E, MA>
101 where
102 E: Encode,
103 MA: MemoryAccess,
104 {
105 TableReader::new(&self.page_ledger, mm)
106 }
107
108 pub fn read_at<E, MA>(&self, address: RecordAddress, mm: &mut MA) -> MemoryResult<E>
110 where
111 E: Encode,
112 MA: MemoryAccess,
113 {
114 let raw_record: RawRecord<E> = mm.read_at(address.page, address.offset)?;
115 Ok(raw_record.data)
116 }
117
118 pub fn delete(
122 &mut self,
123 record: impl Encode,
124 address: RecordAddress,
125 mm: &mut impl MemoryAccess,
126 ) -> MemoryResult<()> {
127 let raw_record = RawRecord::new(record);
128
129 mm.zero(address.page, address.offset, &raw_record)?;
131
132 self.free_segments_ledger
134 .insert_free_segment(address.page, address.offset, &raw_record, mm)
135 }
136
137 pub fn update(
146 &mut self,
147 new_record: impl Encode,
148 old_record: impl Encode,
149 old_address: RecordAddress,
150 mm: &mut impl MemoryAccess,
151 ) -> MemoryResult<RecordAddress> {
152 if new_record.size() == old_record.size() {
153 self.update_in_place(new_record, old_address, mm)
154 } else {
155 self.update_by_realloc(new_record, old_record, old_address, mm)
156 }
157 }
158
159 pub fn iter_raw<'a, MA>(
166 &'a self,
167 alignment: PageOffset,
168 mm: &'a mut MA,
169 ) -> RawTableReader<'a, MA>
170 where
171 MA: MemoryAccess,
172 {
173 RawTableReader::new(&self.page_ledger, alignment, mm)
174 }
175
176 pub fn insert_raw(
182 &mut self,
183 bytes: &[u8],
184 alignment: PageOffset,
185 mm: &mut impl MemoryAccess,
186 ) -> MemoryResult<RecordAddress> {
187 use self::raw_record::RAW_RECORD_HEADER_SIZE;
188
189 let length = bytes.len() as MSize;
190 let total = (RAW_RECORD_HEADER_SIZE + length) as u64;
191 let physical_size_msize = align_up_msize(RAW_RECORD_HEADER_SIZE + length, alignment);
192 let physical_size_u64 = physical_size_msize as u64;
193
194 let (page, offset) = if let Some(segment) = self
196 .free_segments_ledger
197 .find_reusable_segment_raw(length, mm)?
198 {
199 let page = segment.segment.page;
200 let offset = segment.segment.offset;
201 self.free_segments_ledger
202 .commit_reused_space_raw(physical_size_msize, segment, mm)?;
203 (page, offset)
204 } else {
205 let (page, offset) =
206 self.page_ledger
207 .get_page_and_offset_raw(physical_size_u64, alignment, mm)?;
208 self.page_ledger.commit_raw(page, total, alignment, mm)?;
209 (page, offset)
210 };
211 let mut full = Vec::with_capacity(total as usize);
212 full.extend_from_slice(&length.to_le_bytes());
213 full.extend_from_slice(bytes);
214 mm.write_at_raw(page, offset, &full)?;
215 let physical_size = align_up_msize(RAW_RECORD_HEADER_SIZE + length, alignment);
216 let padding = physical_size.saturating_sub(RAW_RECORD_HEADER_SIZE + length);
217 if padding > 0 {
218 let padding_offset = offset + RAW_RECORD_HEADER_SIZE + length;
219 mm.zero_raw(page, padding_offset, padding)?;
220 }
221
222 Ok(RecordAddress { page, offset })
223 }
224
225 pub fn read_raw_at(
227 &self,
228 address: RecordAddress,
229 mm: &mut impl MemoryAccess,
230 ) -> MemoryResult<Vec<u8>> {
231 use self::raw_record::RAW_RECORD_HEADER_SIZE;
232
233 let mut header = [0u8; RAW_RECORD_HEADER_SIZE as usize];
234 mm.read_at_raw(address.page, address.offset, &mut header)?;
235 let length = u16::from_le_bytes(header) as usize;
236 let mut body = vec![0u8; length];
237 mm.read_at_raw(
238 address.page,
239 address.offset + RAW_RECORD_HEADER_SIZE,
240 &mut body,
241 )?;
242 Ok(body)
243 }
244
245 pub fn delete_raw(
249 &mut self,
250 address: RecordAddress,
251 body_len: MSize,
252 alignment: PageOffset,
253 mm: &mut impl MemoryAccess,
254 ) -> MemoryResult<()> {
255 use self::raw_record::RAW_RECORD_HEADER_SIZE;
256
257 let physical_size = align_up_msize(RAW_RECORD_HEADER_SIZE + body_len, alignment);
258 mm.zero_raw(address.page, address.offset, physical_size)?;
259 self.free_segments_ledger.insert_free_segment_raw(
260 address.page,
261 address.offset,
262 physical_size,
263 mm,
264 )
265 }
266
267 pub fn release_pages(
288 self,
289 table_pages: TableRegistryPage,
290 mm: &mut impl MemoryAccess,
291 ) -> MemoryResult<()> {
292 self.page_ledger.release_pages(mm)?;
293 self.free_segments_ledger.release_pages(mm)?;
294 self.index_ledger.release_pages(mm)?;
295 mm.unclaim_page(table_pages.schema_snapshot_page)?;
296 if let Some(page) = table_pages.autoincrement_registry_page {
297 mm.unclaim_page(page)?;
298 }
299 Ok(())
300 }
301
302 pub fn releasable_pages_count(
304 &self,
305 table_pages: TableRegistryPage,
306 mm: &mut impl MemoryAccess,
307 ) -> MemoryResult<usize> {
308 let mut count = self.page_ledger.releasable_pages_count();
309 count += self.free_segments_ledger.releasable_pages_count();
310 count += self.index_ledger.releasable_pages_count(mm)?;
311 count += 1; if table_pages.autoincrement_registry_page.is_some() {
313 count += 1;
314 }
315 Ok(count)
316 }
317
318 pub fn index_ledger(&self) -> &IndexLedger {
320 &self.index_ledger
321 }
322
323 pub fn index_ledger_mut(&mut self) -> &mut IndexLedger {
325 &mut self.index_ledger
326 }
327
328 pub fn schema_snapshot_ledger(&self) -> &SchemaSnapshotLedger {
330 &self.schema_snapshot_ledger
331 }
332
333 pub fn schema_snapshot_ledger_mut(&mut self) -> &mut SchemaSnapshotLedger {
335 &mut self.schema_snapshot_ledger
336 }
337
338 pub fn next_autoincrement(
340 &mut self,
341 column_name: &str,
342 mm: &mut impl MemoryAccess,
343 ) -> MemoryResult<Option<Value>> {
344 if let Some(ledger) = &mut self.auto_increment_ledger {
345 ledger.next(column_name, mm).map(Some)
346 } else {
347 Ok(None)
348 }
349 }
350
351 fn update_in_place(
357 &mut self,
358 record: impl Encode,
359 address: RecordAddress,
360 mm: &mut impl MemoryAccess,
361 ) -> MemoryResult<RecordAddress> {
362 let raw_record = RawRecord::new(record);
363 mm.write_at(address.page, address.offset, &raw_record)?;
364
365 Ok(address)
366 }
367
368 fn update_by_realloc(
374 &mut self,
375 new_record: impl Encode,
376 old_record: impl Encode,
377 old_address: RecordAddress,
378 mm: &mut impl MemoryAccess,
379 ) -> MemoryResult<RecordAddress> {
380 self.delete(old_record, old_address, mm)?;
382
383 self.insert(new_record, mm)
385 }
386
387 fn get_write_position<E>(
389 &mut self,
390 record: &RawRecord<E>,
391 mm: &mut impl MemoryAccess,
392 ) -> MemoryResult<WriteAt>
393 where
394 E: Encode,
395 {
396 if let Some(segment) = self
398 .free_segments_ledger
399 .find_reusable_segment(record, mm)?
400 {
401 return Ok(WriteAt::ReusedSegment(segment));
402 }
403
404 self.page_ledger
406 .get_page_and_offset_for_record(record, mm)
407 .map(|(page, offset)| WriteAt::End(page, offset))
408 }
409
410 fn post_write<E>(
415 &mut self,
416 write_at: WriteAt,
417 record: &RawRecord<E>,
418 mm: &mut impl MemoryAccess,
419 ) -> MemoryResult<()>
420 where
421 E: Encode,
422 {
423 match write_at {
424 WriteAt::ReusedSegment(free_segment) => {
425 self.free_segments_ledger
427 .commit_reused_space(record, free_segment, mm)
428 }
429 WriteAt::End(page, ..) => {
430 self.page_ledger.commit(page, record, mm)
432 }
433 }
434 }
435}
436
437fn align_up_msize(value: MSize, alignment: PageOffset) -> MSize {
441 if alignment == 0 {
442 return value;
443 }
444 value.div_ceil(alignment) * alignment
445}
446
447#[cfg(test)]
449pub(crate) mod test_utils {
450 use wasm_dbms_api::prelude::{
451 DEFAULT_ALIGNMENT, DataSize, DecodeError, Encode, MSize, MemoryError, MemoryResult, Page,
452 PageOffset, TableSchemaSnapshot,
453 };
454
455 use crate::MemoryAccess;
456
457 pub fn write_dummy_schema_snapshot(page: Page, mm: &mut impl MemoryAccess) {
465 let dummy = TableSchemaSnapshot {
466 version: TableSchemaSnapshot::latest_version(),
467 name: "dummy".to_string(),
468 primary_key: "id".to_string(),
469 alignment: 8,
470 columns: vec![],
471 indexes: vec![],
472 };
473 mm.write_at(page, 0, &dummy)
474 .expect("failed to write dummy snapshot");
475 }
476
477 #[derive(Debug, Clone, PartialEq, Eq)]
479 pub struct User {
480 pub id: u32,
481 pub name: String,
482 pub email: String,
483 pub age: u32,
484 }
485
486 impl Encode for User {
487 const SIZE: DataSize = DataSize::Dynamic;
488
489 const ALIGNMENT: PageOffset = DEFAULT_ALIGNMENT;
490
491 fn encode(&'_ self) -> std::borrow::Cow<'_, [u8]> {
492 let mut buf = Vec::new();
493 buf.extend_from_slice(&self.id.to_le_bytes());
495 buf.extend_from_slice(&(self.name.len() as u16).to_le_bytes());
497 buf.extend_from_slice(self.name.as_bytes());
498 buf.extend_from_slice(&(self.email.len() as u16).to_le_bytes());
500 buf.extend_from_slice(self.email.as_bytes());
501 buf.extend_from_slice(&self.age.to_le_bytes());
503 std::borrow::Cow::Owned(buf)
504 }
505
506 fn decode(data: std::borrow::Cow<[u8]>) -> MemoryResult<Self>
507 where
508 Self: Sized,
509 {
510 if data.len() < 12 {
511 return Err(MemoryError::DecodeError(DecodeError::TooShort));
512 }
513 let mut offset = 0;
514 let id = u32::from_le_bytes(data[offset..offset + 4].try_into().unwrap());
516 offset += 4;
517 let name_len =
519 u16::from_le_bytes(data[offset..offset + 2].try_into().unwrap()) as usize;
520 offset += 2;
521 let name = String::from_utf8_lossy(&data[offset..offset + name_len]).to_string();
522 offset += name_len;
523 let email_len =
525 u16::from_le_bytes(data[offset..offset + 2].try_into().unwrap()) as usize;
526 offset += 2;
527 let email = String::from_utf8_lossy(&data[offset..offset + email_len]).to_string();
528 offset += email_len;
529 let age = u32::from_le_bytes(data[offset..offset + 4].try_into().unwrap());
531
532 Ok(User {
533 id,
534 name,
535 email,
536 age,
537 })
538 }
539
540 fn size(&self) -> MSize {
541 (4 + 2 + self.name.len() + 2 + self.email.len() + 4) as MSize
542 }
543 }
544}
545
546#[cfg(test)]
547mod tests {
548
549 use self::test_utils::User;
550 use super::free_segments_ledger::FreeSegment;
551 use super::table_reader::NextRecord;
552 use super::*;
553 use crate::{HeapMemoryProvider, MemoryManager};
554
555 #[test]
556 fn test_should_create_table_registry() {
557 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
558 let schema_snapshot_page = mm.claim_page().expect("failed to get page");
559 let page_ledger_page = mm.claim_page().expect("failed to get page");
560 let free_segments_page = mm.claim_page().expect("failed to get page");
561 let index_registry_page = mm.claim_page().expect("failed to get page");
562 let autoincrement_page = mm.claim_page().expect("failed to get page");
563 super::test_utils::write_dummy_schema_snapshot(schema_snapshot_page, &mut mm);
564 let table_pages = TableRegistryPage {
565 schema_snapshot_page,
566 pages_list_page: page_ledger_page,
567 free_segments_page,
568 index_registry_page,
569 autoincrement_registry_page: Some(autoincrement_page),
570 };
571
572 let registry: MemoryResult<TableRegistry> = TableRegistry::load(table_pages, &mut mm);
573 assert!(registry.is_ok());
574 }
575
576 #[test]
577 fn test_should_get_write_at_end() {
578 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
579 let mut registry = registry(&mut mm);
580
581 let record = RawRecord::new(User {
582 id: 1,
583 name: "Test".to_string(),
584 email: "new_user@example.com".to_string(),
585 age: 25,
586 });
587 let write_at = registry
588 .get_write_position(&record, &mut mm)
589 .expect("failed to get write at");
590
591 assert!(matches!(write_at, WriteAt::End(_, 0)));
592 }
593
594 #[test]
595 fn test_should_get_write_at_free_segment() {
596 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
597 let mut registry = registry(&mut mm);
598
599 let record = RawRecord::new(User {
600 id: 1,
601 name: "Test".to_string(),
602 email: "new_user@example.com".to_string(),
603 age: 25,
604 });
605 let (page, _) = registry
607 .page_ledger
608 .get_page_and_offset_for_record(&record, &mut mm)
609 .expect("failed to get page and offset");
610 registry
611 .page_ledger
612 .commit(page, &record, &mut mm)
613 .expect("failed to commit page ledger");
614 registry
616 .free_segments_ledger
617 .insert_free_segment(page, 256, &record, &mut mm)
618 .expect("failed to insert free segment");
619
620 let write_at = registry
621 .get_write_position(&record, &mut mm)
622 .expect("failed to get write at");
623
624 let reused_segment = match write_at {
625 WriteAt::ReusedSegment(segment) => segment.segment,
626 _ => panic!("expected reused segment"),
627 };
628
629 assert_eq!(
630 reused_segment,
631 FreeSegment {
632 page,
633 offset: 256,
634 size: 64, }
636 );
637 }
638
639 #[test]
640 fn test_should_insert_record_into_table_registry() {
641 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
642 let mut registry = registry(&mut mm);
643
644 let record = User {
645 id: 1,
646 name: "Test".to_string(),
647 email: "new_user@example.com".to_string(),
648 age: 25,
649 };
650
651 assert!(registry.insert(record, &mut mm).is_ok());
653 }
654
655 #[test]
656 fn test_should_manage_to_insert_users_to_exceed_one_page() {
657 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
658 let mut registry = registry(&mut mm);
659
660 for id in 0..4000 {
661 let record = User {
662 id,
663 name: format!("User {}", id),
664 email: "new_user@example.com".to_string(),
665 age: 20 + id,
666 };
667 registry
668 .insert(record, &mut mm)
669 .expect("failed to insert record");
670 }
671 }
672
673 #[test]
674 fn test_should_delete_record() {
675 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
676 let mut registry = registry(&mut mm);
677
678 let record = User {
679 id: 1,
680 name: "Test".to_string(),
681 email: "new_user@example.com".to_string(),
682 age: 25,
683 };
684
685 registry
687 .insert(record.clone(), &mut mm)
688 .expect("failed to insert");
689
690 let mut reader = registry.read(&mut mm);
692 let next_record: NextRecord<User> = reader
693 .try_next()
694 .expect("failed to read")
695 .expect("no record");
696 let page = next_record.page;
697 let offset = next_record.offset;
698 let record = next_record.record;
699 let raw_user = RawRecord::new(record.clone());
700 let raw_user_size = raw_user.size();
701
702 assert!(
704 registry
705 .delete(record, RecordAddress { page, offset }, &mut mm)
706 .is_ok()
707 );
708
709 let mut reader = registry.read::<User, _>(&mut mm);
711 assert!(reader.try_next().expect("failed to read").is_none());
712
713 let free_segment = registry
715 .free_segments_ledger
716 .find_reusable_segment(
717 &User {
718 id: 2,
719 name: "Test".to_string(),
720 email: "new_user@example.com".to_string(),
721 age: 25,
722 },
723 &mut mm,
724 )
725 .expect("failed to find free segment")
726 .expect("could not find the free segment after free")
727 .segment;
728 assert_eq!(free_segment.page, page);
729 assert_eq!(free_segment.offset, offset);
730 assert_eq!(free_segment.size, 64); let mut buffer = vec![0u8; raw_user_size as usize];
734 mm.read_at_raw(page, offset, &mut buffer)
735 .expect("failed to read memory");
736 assert!(buffer.iter().all(|&b| b == 0));
737 }
738
739 #[test]
740 fn test_read_at_returns_record_at_address() {
741 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
742 let mut registry = registry(&mut mm);
743 let record = User {
744 id: 1,
745 name: "Alice".to_string(),
746 email: "alice@example.com".to_string(),
747 age: 30,
748 };
749
750 let address = registry
751 .insert(record.clone(), &mut mm)
752 .expect("failed to insert record");
753
754 let stored: User = registry
755 .read_at(address, &mut mm)
756 .expect("failed to read record");
757 assert_eq!(stored, record);
758 }
759
760 #[test]
761 fn test_read_at_after_update_returns_updated_record() {
762 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
763 let mut registry = registry(&mut mm);
764 let old_record = User {
765 id: 1,
766 name: "Alice".to_string(),
767 email: "alice@example.com".to_string(),
768 age: 30,
769 };
770 let new_record = User {
771 id: 1,
772 name: "Alice Updated".to_string(),
773 email: "alice.updated@example.com".to_string(),
774 age: 31,
775 };
776
777 let old_address = registry
778 .insert(old_record.clone(), &mut mm)
779 .expect("failed to insert record");
780 let new_address = registry
781 .update(new_record.clone(), old_record, old_address, &mut mm)
782 .expect("failed to update record");
783
784 let stored: User = registry
785 .read_at(new_address, &mut mm)
786 .expect("failed to read updated record");
787 assert_eq!(stored, new_record);
788 }
789
790 #[test]
791 fn test_should_update_record_in_place() {
792 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
793 let mut registry = registry(&mut mm);
794
795 let old_record = User {
796 id: 1,
797 name: "John".to_string(),
798 email: "new_user@example.com".to_string(),
799 age: 28,
800 };
801 let new_record = User {
802 id: 1,
803 name: "Mark".to_string(), email: "new_user@example.com".to_string(),
805 age: 30,
806 };
807
808 registry
810 .insert(old_record.clone(), &mut mm)
811 .expect("failed to insert");
812
813 let mut reader = registry.read::<User, _>(&mut mm);
815 let next_record = reader
816 .try_next()
817 .expect("failed to read")
818 .expect("no record");
819 let page = next_record.page;
820 let offset = next_record.offset;
821
822 let old_address = RecordAddress { page, offset };
824 let new_location = registry
825 .update(
826 new_record.clone(),
827 next_record.record.clone(),
828 old_address,
829 &mut mm,
830 )
831 .expect("failed to update record");
832 assert_eq!(new_location, old_address); let mut reader = registry.read::<User, _>(&mut mm);
836 let next_record = reader
837 .try_next()
838 .expect("failed to read")
839 .expect("no record");
840 assert_eq!(next_record.page, page); assert_eq!(next_record.offset, offset); assert_eq!(next_record.record, new_record);
843 }
844
845 #[test]
846 fn test_should_update_record_reallocating() {
847 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
848 let mut registry = registry(&mut mm);
849
850 let old_record = User {
851 id: 1,
852 name: "John".to_string(),
853 email: "new_user@example.com".to_string(),
854 age: 28,
855 };
856 let extra_user = User {
858 id: 2,
859 name: "Extra".to_string(),
860 email: "new_user@example.com".to_string(),
861 age: 25,
862 };
863 let new_record = User {
864 id: 1,
865 name: "Alexanderejruwgjowergjioewrgjioewrigjewriogjweoirgjiowerjgoiwerjiogewirogjowejrgiwer".to_string(), email: "new_user@example.com".to_string(),
867 age: 30,
868 };
869
870 registry
872 .insert(old_record.clone(), &mut mm)
873 .expect("failed to insert");
874 registry
876 .insert(extra_user.clone(), &mut mm)
877 .expect("failed to insert extra user");
878
879 let mut reader = registry.read::<User, _>(&mut mm);
881 let old_record_from_db = reader
882 .try_next()
883 .expect("failed to read")
884 .expect("no record");
885 assert_eq!(old_record_from_db.record, old_record);
886 let page = old_record_from_db.page;
887 let offset = old_record_from_db.offset;
888
889 let old_address = RecordAddress { page, offset };
891 let new_location = registry
892 .update(
893 new_record.clone(),
894 old_record_from_db.record.clone(),
895 old_address,
896 &mut mm,
897 )
898 .expect("failed to update record");
899 assert_ne!(new_location, old_address); let mut reader = registry.read::<User, _>(&mut mm);
903
904 let _ = reader
906 .try_next()
907 .expect("failed to read")
908 .expect("no record");
909
910 let updated_record = reader
911 .try_next()
912 .expect("failed to read")
913 .expect("no record");
914 assert_ne!(updated_record.offset, offset); assert_eq!(updated_record.record, new_record);
916 }
917
918 #[test]
919 fn test_should_insert_delete_insert_many() {
920 const COUNT: u32 = 1_000;
921 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
922 let mut registry = registry(&mut mm);
923 for id in 0..COUNT {
924 let record = User {
925 id,
926 name: format!("User {id}"),
927 email: format!("user_{id}@example.com"),
928 age: 20,
929 };
930
931 registry
933 .insert(record.clone(), &mut mm)
934 .expect("failed to insert");
935 }
936
937 for id in (0..COUNT).filter(|id| id % 2 == 1) {
939 let record = User {
940 id,
941 name: format!("User {id}"),
942 email: format!("user_{id}@example.com"),
943 age: 20,
944 };
945 let mut reader = registry.read::<User, _>(&mut mm);
947 let mut deleted = false;
948 while let Some(next_record) = reader.try_next().expect("failed to read") {
949 if next_record.record.id == id {
950 registry
951 .delete(
952 record.clone(),
953 RecordAddress {
954 page: next_record.page,
955 offset: next_record.offset,
956 },
957 &mut mm,
958 )
959 .expect("failed to delete");
960 deleted = true;
961 break;
962 }
963 }
964 assert!(deleted, "record with id {} was not found", id);
965 }
966
967 for id in (0..COUNT).filter(|id| id % 2 == 0) {
969 let record = User {
970 id,
971 name: format!("User {id}"),
972 email: format!("user_{id}@example.com"),
973 age: 20,
974 };
975 let mut reader = registry.read::<User, _>(&mut mm);
977 let mut deleted = false;
978 while let Some(next_record) = reader.try_next().expect("failed to read") {
979 if next_record.record.id == id {
980 registry
981 .delete(
982 record.clone(),
983 RecordAddress {
984 page: next_record.page,
985 offset: next_record.offset,
986 },
987 &mut mm,
988 )
989 .expect("failed to delete");
990 deleted = true;
991 break;
992 }
993 }
994 assert!(deleted, "record with id {} was not found", id);
995 }
996
997 for id in 0..COUNT {
999 let record = User {
1000 id,
1001 name: format!("User {id}"),
1002 email: format!("user_{id}@example.com"),
1003 age: 20,
1004 };
1005
1006 registry
1008 .insert(record.clone(), &mut mm)
1009 .expect("failed to insert");
1010 }
1011 }
1012
1013 #[test]
1014 fn test_should_reduce_free_segment_size_with_padding() {
1015 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
1016 let mut registry = registry(&mut mm);
1017
1018 let long_name = vec!['A'; 1024].into_iter().collect::<String>();
1020 let record = User {
1021 id: 1,
1022 name: "Test User".to_string(),
1023 email: long_name,
1024 age: 30,
1025 };
1026 registry
1027 .insert(record.clone(), &mut mm)
1028 .expect("failed to insert");
1029 let mut reader = registry.read::<User, _>(&mut mm);
1031 let next_record = reader
1032 .try_next()
1033 .expect("failed to read")
1034 .expect("no record");
1035 registry
1037 .delete(
1038 next_record.record,
1039 RecordAddress {
1040 page: next_record.page,
1041 offset: next_record.offset,
1042 },
1043 &mut mm,
1044 )
1045 .expect("failed to delete");
1046
1047 let raw_record = RawRecord::new(record.clone());
1049 let free_segment = registry
1050 .free_segments_ledger
1051 .find_reusable_segment(&raw_record, &mut mm)
1052 .expect("failed to find reusable segment")
1053 .expect("could not find the free segment after free")
1054 .segment;
1055 assert!(free_segment.size >= 1024);
1057 let previous_size = free_segment.size;
1058
1059 let small_record = User {
1061 id: 2,
1062 name: "Bob The Builder".to_string(),
1063 email: "bob@hotmail.com".to_string(),
1064 age: 22,
1065 };
1066 registry
1067 .insert(small_record.clone(), &mut mm)
1068 .expect("failed to insert small user");
1069
1070 let free_segment_after = registry
1072 .free_segments_ledger
1073 .find_reusable_segment(&small_record, &mut mm)
1074 .expect("failed to find reusable segment")
1075 .expect("could not find the free segment after inserting small user")
1076 .segment;
1077
1078 assert_eq!(
1080 free_segment_after.offset, 64,
1081 "expected offset to be 64, but had: {}",
1082 free_segment_after.offset
1083 ); assert_eq!(
1085 free_segment_after.size,
1086 previous_size - 64,
1087 "Expected free segment to have size: {} but got: {}",
1088 previous_size - 64,
1089 free_segment_after.size
1090 );
1091 }
1092
1093 fn registry(mm: &mut MemoryManager<HeapMemoryProvider>) -> TableRegistry {
1094 let schema_snapshot_page = mm.claim_page().expect("failed to get page");
1095 let page_ledger_page = mm.claim_page().expect("failed to get page");
1096 let free_segments_page = mm.claim_page().expect("failed to get page");
1097 let index_registry_page = mm.claim_page().expect("failed to get page");
1098 let autoincrement_page = mm.claim_page().expect("failed to get page");
1099 super::test_utils::write_dummy_schema_snapshot(schema_snapshot_page, mm);
1100 let table_pages = TableRegistryPage {
1101 schema_snapshot_page,
1102 pages_list_page: page_ledger_page,
1103 free_segments_page,
1104 index_registry_page,
1105 autoincrement_registry_page: Some(autoincrement_page),
1106 };
1107
1108 TableRegistry::load(table_pages, mm).expect("failed to load")
1109 }
1110
1111 fn registry_with_autoincrement(mm: &mut MemoryManager<HeapMemoryProvider>) -> TableRegistry {
1114 use crate::SchemaRegistry;
1115
1116 let mut schema = SchemaRegistry::load(mm).expect("failed to load schema");
1117 let pages = schema
1118 .register_table::<AutoincUser>(mm)
1119 .expect("failed to register table");
1120 TableRegistry::load(pages, mm).expect("failed to load")
1121 }
1122
1123 fn registry_without_autoincrement(mm: &mut MemoryManager<HeapMemoryProvider>) -> TableRegistry {
1125 let schema_snapshot_page = mm.claim_page().expect("failed to get page");
1126 let page_ledger_page = mm.claim_page().expect("failed to get page");
1127 let free_segments_page = mm.claim_page().expect("failed to get page");
1128 let index_registry_page = mm.claim_page().expect("failed to get page");
1129 super::test_utils::write_dummy_schema_snapshot(schema_snapshot_page, mm);
1130 let table_pages = TableRegistryPage {
1131 schema_snapshot_page,
1132 pages_list_page: page_ledger_page,
1133 free_segments_page,
1134 index_registry_page,
1135 autoincrement_registry_page: None,
1136 };
1137
1138 TableRegistry::load(table_pages, mm).expect("failed to load")
1139 }
1140
1141 use candid::CandidType;
1144 use serde::{Deserialize, Serialize};
1145 use wasm_dbms_api::prelude::{
1146 ColumnDef, DbmsResult, IndexDef, InsertRecord, NoForeignFetcher, TableColumns, TableRecord,
1147 TableSchema, UpdateRecord,
1148 };
1149
1150 #[derive(Clone, CandidType)]
1151 struct AutoincUser;
1152
1153 impl Encode for AutoincUser {
1154 const SIZE: wasm_dbms_api::prelude::DataSize = wasm_dbms_api::prelude::DataSize::Dynamic;
1155 const ALIGNMENT: PageOffset = wasm_dbms_api::prelude::DEFAULT_ALIGNMENT;
1156
1157 fn encode(&'_ self) -> std::borrow::Cow<'_, [u8]> {
1158 std::borrow::Cow::Owned(vec![])
1159 }
1160
1161 fn decode(_data: std::borrow::Cow<[u8]>) -> MemoryResult<Self>
1162 where
1163 Self: Sized,
1164 {
1165 Ok(Self)
1166 }
1167
1168 fn size(&self) -> wasm_dbms_api::prelude::MSize {
1169 0
1170 }
1171 }
1172
1173 #[derive(Clone, CandidType, Deserialize)]
1174 struct AutoincUserRecord;
1175
1176 impl TableRecord for AutoincUserRecord {
1177 type Schema = AutoincUser;
1178
1179 fn from_values(_values: TableColumns) -> Self {
1180 Self
1181 }
1182
1183 fn to_values(&self) -> Vec<(ColumnDef, Value)> {
1184 vec![]
1185 }
1186 }
1187
1188 #[derive(Clone, CandidType, Serialize)]
1189 struct AutoincUserInsert;
1190
1191 impl InsertRecord for AutoincUserInsert {
1192 type Record = AutoincUserRecord;
1193 type Schema = AutoincUser;
1194
1195 fn from_values(_values: &[(ColumnDef, Value)]) -> DbmsResult<Self> {
1196 Ok(Self)
1197 }
1198
1199 fn into_values(self) -> Vec<(ColumnDef, Value)> {
1200 vec![]
1201 }
1202
1203 fn into_record(self) -> Self::Schema {
1204 AutoincUser
1205 }
1206 }
1207
1208 #[derive(Clone, CandidType, Serialize)]
1209 struct AutoincUserUpdate;
1210
1211 impl UpdateRecord for AutoincUserUpdate {
1212 type Record = AutoincUserRecord;
1213 type Schema = AutoincUser;
1214
1215 fn from_values(
1216 _values: &[(ColumnDef, Value)],
1217 _where_clause: Option<wasm_dbms_api::prelude::Filter>,
1218 ) -> Self {
1219 Self
1220 }
1221
1222 fn update_values(&self) -> Vec<(ColumnDef, Value)> {
1223 vec![]
1224 }
1225
1226 fn where_clause(&self) -> Option<wasm_dbms_api::prelude::Filter> {
1227 None
1228 }
1229 }
1230
1231 impl TableSchema for AutoincUser {
1232 type Record = AutoincUserRecord;
1233 type Insert = AutoincUserInsert;
1234 type Update = AutoincUserUpdate;
1235 type ForeignFetcher = NoForeignFetcher;
1236
1237 fn table_name() -> &'static str {
1238 "autoinc_users"
1239 }
1240
1241 fn columns() -> &'static [ColumnDef] {
1242 use wasm_dbms_api::prelude::DataTypeKind;
1243
1244 &[ColumnDef {
1245 name: "id",
1246 data_type: DataTypeKind::Uint32,
1247 auto_increment: true,
1248 nullable: false,
1249 primary_key: true,
1250 unique: true,
1251 foreign_key: None,
1252 default: None,
1253 renamed_from: &[],
1254 }]
1255 }
1256
1257 fn primary_key() -> &'static str {
1258 "id"
1259 }
1260
1261 fn indexes() -> &'static [IndexDef] {
1262 &[IndexDef(&["id"])]
1263 }
1264
1265 fn to_values(self) -> Vec<(ColumnDef, Value)> {
1266 vec![]
1267 }
1268
1269 fn sanitizer(
1270 _column_name: &'static str,
1271 ) -> Option<Box<dyn wasm_dbms_api::prelude::Sanitize>> {
1272 None
1273 }
1274
1275 fn validator(
1276 _column_name: &'static str,
1277 ) -> Option<Box<dyn wasm_dbms_api::prelude::Validate>> {
1278 None
1279 }
1280 }
1281
1282 #[test]
1285 fn test_next_autoincrement_returns_sequential_values() {
1286 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
1287 let mut registry = registry_with_autoincrement(&mut mm);
1288
1289 let v1 = registry
1290 .next_autoincrement("id", &mut mm)
1291 .expect("failed")
1292 .expect("expected Some");
1293 let v2 = registry
1294 .next_autoincrement("id", &mut mm)
1295 .expect("failed")
1296 .expect("expected Some");
1297 let v3 = registry
1298 .next_autoincrement("id", &mut mm)
1299 .expect("failed")
1300 .expect("expected Some");
1301
1302 assert_eq!(v1, Value::Uint32(1u32.into()));
1303 assert_eq!(v2, Value::Uint32(2u32.into()));
1304 assert_eq!(v3, Value::Uint32(3u32.into()));
1305 }
1306
1307 #[test]
1308 fn test_next_autoincrement_returns_none_without_ledger() {
1309 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
1310 let mut registry = registry_without_autoincrement(&mut mm);
1311
1312 let result = registry.next_autoincrement("id", &mut mm).expect("failed");
1313 assert!(result.is_none());
1314 }
1315
1316 #[test]
1317 fn test_next_autoincrement_persists_across_reload() {
1318 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
1319
1320 use crate::SchemaRegistry;
1321 let mut schema = SchemaRegistry::load(&mut mm).expect("failed to load schema");
1322 let pages = schema
1323 .register_table::<AutoincUser>(&mut mm)
1324 .expect("failed to register table");
1325
1326 let mut registry = TableRegistry::load(pages, &mut mm).expect("failed to load");
1328 for _ in 0..5 {
1329 let _ = registry
1330 .next_autoincrement("id", &mut mm)
1331 .expect("next failed");
1332 }
1333
1334 let mut reloaded = TableRegistry::load(pages, &mut mm).expect("failed to reload");
1336 let value = reloaded
1337 .next_autoincrement("id", &mut mm)
1338 .expect("failed")
1339 .expect("expected Some");
1340 assert_eq!(value, Value::Uint32(6u32.into()));
1341 }
1342
1343 #[test]
1344 fn test_next_autoincrement_overflow_returns_error() {
1345 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
1346
1347 let schema_snapshot_page = mm.claim_page().expect("failed to get page");
1349 let page_ledger_page = mm.claim_page().expect("failed to get page");
1350 let free_segments_page = mm.claim_page().expect("failed to get page");
1351 let index_registry_page = mm.claim_page().expect("failed to get page");
1352 let autoinc_page = mm.claim_page().expect("failed to get page");
1353
1354 {
1358 let mut registry_data = super::autoincrement_ledger::AutoincrementLedger::init::<
1359 Uint8AutoincSchema,
1360 >(autoinc_page, &mut mm)
1361 .expect("failed to init autoinc ledger");
1362
1363 for _ in 0..255 {
1365 let _ = registry_data.next("val", &mut mm).expect("next failed");
1366 }
1367 }
1368
1369 IndexLedger::init(index_registry_page, &[], &mut mm).expect("failed to init index ledger");
1371
1372 super::test_utils::write_dummy_schema_snapshot(schema_snapshot_page, &mut mm);
1373
1374 let table_pages = TableRegistryPage {
1375 schema_snapshot_page,
1376 pages_list_page: page_ledger_page,
1377 free_segments_page,
1378 index_registry_page,
1379 autoincrement_registry_page: Some(autoinc_page),
1380 };
1381
1382 let mut registry = TableRegistry::load(table_pages, &mut mm).expect("failed to load");
1383 let result = registry.next_autoincrement("val", &mut mm);
1384 assert!(result.is_err());
1385 assert!(matches!(
1386 result.unwrap_err(),
1387 wasm_dbms_api::prelude::MemoryError::AutoincrementOverflow(_)
1388 ));
1389 }
1390
1391 #[derive(Clone, CandidType)]
1394 struct Uint8AutoincSchema;
1395
1396 impl Encode for Uint8AutoincSchema {
1397 const SIZE: wasm_dbms_api::prelude::DataSize = wasm_dbms_api::prelude::DataSize::Dynamic;
1398 const ALIGNMENT: PageOffset = wasm_dbms_api::prelude::DEFAULT_ALIGNMENT;
1399
1400 fn encode(&'_ self) -> std::borrow::Cow<'_, [u8]> {
1401 std::borrow::Cow::Owned(vec![])
1402 }
1403
1404 fn decode(_data: std::borrow::Cow<[u8]>) -> MemoryResult<Self>
1405 where
1406 Self: Sized,
1407 {
1408 Ok(Self)
1409 }
1410
1411 fn size(&self) -> wasm_dbms_api::prelude::MSize {
1412 0
1413 }
1414 }
1415
1416 #[derive(Clone, CandidType, Deserialize)]
1417 struct Uint8AutoincSchemaRecord;
1418
1419 impl TableRecord for Uint8AutoincSchemaRecord {
1420 type Schema = Uint8AutoincSchema;
1421
1422 fn from_values(_values: TableColumns) -> Self {
1423 Self
1424 }
1425
1426 fn to_values(&self) -> Vec<(ColumnDef, Value)> {
1427 vec![]
1428 }
1429 }
1430
1431 #[derive(Clone, CandidType, Serialize)]
1432 struct Uint8AutoincSchemaInsert;
1433
1434 impl InsertRecord for Uint8AutoincSchemaInsert {
1435 type Record = Uint8AutoincSchemaRecord;
1436 type Schema = Uint8AutoincSchema;
1437
1438 fn from_values(_values: &[(ColumnDef, Value)]) -> DbmsResult<Self> {
1439 Ok(Self)
1440 }
1441
1442 fn into_values(self) -> Vec<(ColumnDef, Value)> {
1443 vec![]
1444 }
1445
1446 fn into_record(self) -> Self::Schema {
1447 Uint8AutoincSchema
1448 }
1449 }
1450
1451 #[derive(Clone, CandidType, Serialize)]
1452 struct Uint8AutoincSchemaUpdate;
1453
1454 impl UpdateRecord for Uint8AutoincSchemaUpdate {
1455 type Record = Uint8AutoincSchemaRecord;
1456 type Schema = Uint8AutoincSchema;
1457
1458 fn from_values(
1459 _values: &[(ColumnDef, Value)],
1460 _where_clause: Option<wasm_dbms_api::prelude::Filter>,
1461 ) -> Self {
1462 Self
1463 }
1464
1465 fn update_values(&self) -> Vec<(ColumnDef, Value)> {
1466 vec![]
1467 }
1468
1469 fn where_clause(&self) -> Option<wasm_dbms_api::prelude::Filter> {
1470 None
1471 }
1472 }
1473
1474 impl TableSchema for Uint8AutoincSchema {
1475 type Record = Uint8AutoincSchemaRecord;
1476 type Insert = Uint8AutoincSchemaInsert;
1477 type Update = Uint8AutoincSchemaUpdate;
1478 type ForeignFetcher = NoForeignFetcher;
1479
1480 fn table_name() -> &'static str {
1481 "uint8_autoinc_schema"
1482 }
1483
1484 fn columns() -> &'static [ColumnDef] {
1485 use wasm_dbms_api::prelude::DataTypeKind;
1486
1487 &[ColumnDef {
1488 name: "val",
1489 data_type: DataTypeKind::Uint8,
1490 auto_increment: true,
1491 nullable: false,
1492 primary_key: true,
1493 unique: true,
1494 foreign_key: None,
1495 default: None,
1496 renamed_from: &[],
1497 }]
1498 }
1499
1500 fn primary_key() -> &'static str {
1501 "val"
1502 }
1503
1504 fn indexes() -> &'static [IndexDef] {
1505 &[IndexDef(&["val"])]
1506 }
1507
1508 fn to_values(self) -> Vec<(ColumnDef, Value)> {
1509 vec![]
1510 }
1511
1512 fn sanitizer(
1513 _column_name: &'static str,
1514 ) -> Option<Box<dyn wasm_dbms_api::prelude::Sanitize>> {
1515 None
1516 }
1517
1518 fn validator(
1519 _column_name: &'static str,
1520 ) -> Option<Box<dyn wasm_dbms_api::prelude::Validate>> {
1521 None
1522 }
1523 }
1524
1525 use wasm_dbms_api::prelude::{DataSize, DecodeError, MSize, MemoryError};
1526
1527 #[derive(Debug, Clone, PartialEq, Eq)]
1531 struct FixedSizeRecord {
1532 id: u64,
1533 timestamp: u64,
1534 tag: u8,
1535 }
1536
1537 impl Encode for FixedSizeRecord {
1538 const SIZE: DataSize = DataSize::Fixed(17);
1539 const ALIGNMENT: PageOffset = 17;
1540
1541 fn encode(&'_ self) -> std::borrow::Cow<'_, [u8]> {
1542 let mut buf = Vec::with_capacity(17);
1543 buf.extend_from_slice(&self.id.to_le_bytes());
1544 buf.extend_from_slice(&self.timestamp.to_le_bytes());
1545 buf.push(self.tag);
1546 std::borrow::Cow::Owned(buf)
1547 }
1548
1549 fn decode(data: std::borrow::Cow<[u8]>) -> MemoryResult<Self>
1550 where
1551 Self: Sized,
1552 {
1553 if data.len() < 17 {
1554 return Err(MemoryError::DecodeError(DecodeError::TooShort));
1555 }
1556 let id = u64::from_le_bytes(data[0..8].try_into().unwrap());
1557 let timestamp = u64::from_le_bytes(data[8..16].try_into().unwrap());
1558 let tag = data[16];
1559 Ok(Self { id, timestamp, tag })
1560 }
1561
1562 fn size(&self) -> MSize {
1563 17
1564 }
1565 }
1566
1567 #[test]
1568 fn test_should_insert_multiple_fixed_size_records() {
1569 let mut mm = MemoryManager::init(HeapMemoryProvider::default());
1570 let mut registry = registry(&mut mm);
1571
1572 for i in 0..10 {
1573 let record = FixedSizeRecord {
1574 id: i,
1575 timestamp: 1000 + i,
1576 tag: (i % 2) as u8,
1577 };
1578 registry
1579 .insert(record, &mut mm)
1580 .unwrap_or_else(|e| panic!("failed to insert record {i}: {e}"));
1581 }
1582
1583 let mut reader = registry.read::<FixedSizeRecord, _>(&mut mm);
1585 let mut count = 0;
1586 while let Some(next) = reader.try_next().expect("failed to read") {
1587 assert_eq!(next.record.id, count);
1588 count += 1;
1589 }
1590 assert_eq!(count, 10);
1591 }
1592}