1use crate::entry::{Entry, Key, Value};
4use crate::error::{QdbError, Result};
5use dashmap::DashMap;
6use parking_lot::RwLock;
7use qft::{QftBuilder, QftFile};
8use std::collections::HashMap;
9use std::fs::{self, File};
10use std::io::{BufReader, BufWriter, Read, Write};
11use std::path::{Path, PathBuf};
12use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
13use std::sync::Arc;
14
15pub trait Backend: Send + Sync {
21 fn get(&self, key: &Key) -> Result<Option<Entry>>;
23
24 fn put(&self, entry: Entry) -> Result<()>;
26
27 fn delete(&self, key: &Key) -> Result<bool>;
29
30 fn exists(&self, key: &Key) -> Result<bool>;
32
33 fn keys(&self) -> Result<Vec<Key>>;
35
36 fn len(&self) -> Result<usize>;
38
39 fn is_empty(&self) -> Result<bool> {
41 Ok(self.len()? == 0)
42 }
43
44 fn flush(&self) -> Result<()>;
46
47 fn close(&self) -> Result<()>;
49}
50
51pub struct MemoryBackend {
57 data: DashMap<Vec<u8>, Entry>,
58 closed: AtomicBool,
59}
60
61impl MemoryBackend {
62 pub fn new() -> Self {
64 Self {
65 data: DashMap::new(),
66 closed: AtomicBool::new(false),
67 }
68 }
69
70 fn check_closed(&self) -> Result<()> {
71 if self.closed.load(Ordering::Acquire) {
72 return Err(QdbError::Closed);
73 }
74 Ok(())
75 }
76}
77
78impl Default for MemoryBackend {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84impl Backend for MemoryBackend {
85 fn get(&self, key: &Key) -> Result<Option<Entry>> {
86 self.check_closed()?;
87 let key_bytes = key.to_bytes();
88 Ok(self.data.get(&key_bytes).map(|e| e.value().clone()))
89 }
90
91 fn put(&self, entry: Entry) -> Result<()> {
92 self.check_closed()?;
93 let key_bytes = entry.key.to_bytes();
94 self.data.insert(key_bytes, entry);
95 Ok(())
96 }
97
98 fn delete(&self, key: &Key) -> Result<bool> {
99 self.check_closed()?;
100 let key_bytes = key.to_bytes();
101 Ok(self.data.remove(&key_bytes).is_some())
102 }
103
104 fn exists(&self, key: &Key) -> Result<bool> {
105 self.check_closed()?;
106 let key_bytes = key.to_bytes();
107 Ok(self.data.contains_key(&key_bytes))
108 }
109
110 fn keys(&self) -> Result<Vec<Key>> {
111 self.check_closed()?;
112 Ok(self.data.iter().map(|e| e.value().key.clone()).collect())
113 }
114
115 fn len(&self) -> Result<usize> {
116 self.check_closed()?;
117 Ok(self.data.len())
118 }
119
120 fn flush(&self) -> Result<()> {
121 self.check_closed()?;
122 Ok(()) }
124
125 fn close(&self) -> Result<()> {
126 self.closed.store(true, Ordering::Release);
127 self.data.clear();
128 Ok(())
129 }
130}
131
132pub struct DiskBackend {
138 path: PathBuf,
139 index: RwLock<HashMap<Vec<u8>, PathBuf>>,
140 closed: AtomicBool,
141 entry_count: AtomicU64,
142}
143
144impl DiskBackend {
145 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
147 let path = path.as_ref().to_path_buf();
148
149 fs::create_dir_all(&path)?;
151
152 let mut index = HashMap::new();
153 let mut count = 0u64;
154
155 if let Ok(entries) = fs::read_dir(&path) {
157 for entry in entries.flatten() {
158 let file_path = entry.path();
159 if file_path.extension().map_or(false, |e| e == "qdb") {
160 if let Ok(key_bytes) = Self::read_key_from_file(&file_path) {
161 index.insert(key_bytes, file_path);
162 count += 1;
163 }
164 }
165 }
166 }
167
168 Ok(Self {
169 path,
170 index: RwLock::new(index),
171 closed: AtomicBool::new(false),
172 entry_count: AtomicU64::new(count),
173 })
174 }
175
176 fn check_closed(&self) -> Result<()> {
177 if self.closed.load(Ordering::Acquire) {
178 return Err(QdbError::Closed);
179 }
180 Ok(())
181 }
182
183 fn key_to_filename(key: &Key) -> String {
184 let hash = key.hash();
185 format!("{}.qdb", hex::encode(&hash[..16]))
186 }
187
188 fn read_key_from_file(path: &Path) -> Result<Vec<u8>> {
189 let file = File::open(path)?;
190 let mut reader = BufReader::new(file);
191
192 let mut magic = [0u8; 4];
194 reader.read_exact(&mut magic)?;
195 if &magic != b"QDB\x01" {
196 return Err(QdbError::BackendError("Invalid QDB file".to_string()));
197 }
198
199 let mut key_len_bytes = [0u8; 4];
201 reader.read_exact(&mut key_len_bytes)?;
202 let key_len = u32::from_le_bytes(key_len_bytes) as usize;
203
204 let mut key_bytes = vec![0u8; key_len];
206 reader.read_exact(&mut key_bytes)?;
207
208 Ok(key_bytes)
209 }
210
211 fn write_entry_to_file(path: &Path, entry: &Entry) -> Result<()> {
212 let file = File::create(path)?;
213 let mut writer = BufWriter::new(file);
214
215 writer.write_all(b"QDB\x01")?;
217
218 let key_bytes = entry.key.to_bytes();
220 writer.write_all(&(key_bytes.len() as u32).to_le_bytes())?;
221 writer.write_all(&key_bytes)?;
222
223 let metadata_json = serde_json::to_vec(&EntryMetadata {
225 entry_type: entry.entry_type,
226 created_at: entry.created_at,
227 modified_at: entry.modified_at,
228 version: entry.version,
229 metadata: entry.metadata.clone(),
230 })?;
231 writer.write_all(&(metadata_json.len() as u32).to_le_bytes())?;
232 writer.write_all(&metadata_json)?;
233
234 let value_bytes = entry.value.to_bytes()?;
236 writer.write_all(&(value_bytes.len() as u64).to_le_bytes())?;
237 writer.write_all(&value_bytes)?;
238
239 let mut hasher = blake3::Hasher::new();
241 hasher.update(&key_bytes);
242 hasher.update(&metadata_json);
243 hasher.update(&value_bytes);
244 let checksum = hasher.finalize();
245 writer.write_all(checksum.as_bytes())?;
246
247 writer.flush()?;
248 Ok(())
249 }
250
251 fn read_entry_from_file(path: &Path) -> Result<Entry> {
252 let file = File::open(path)?;
253 let mut reader = BufReader::new(file);
254
255 let mut magic = [0u8; 4];
257 reader.read_exact(&mut magic)?;
258 if &magic != b"QDB\x01" {
259 return Err(QdbError::BackendError("Invalid QDB file".to_string()));
260 }
261
262 let mut key_len_bytes = [0u8; 4];
264 reader.read_exact(&mut key_len_bytes)?;
265 let key_len = u32::from_le_bytes(key_len_bytes) as usize;
266 let mut key_bytes = vec![0u8; key_len];
267 reader.read_exact(&mut key_bytes)?;
268
269 let mut meta_len_bytes = [0u8; 4];
271 reader.read_exact(&mut meta_len_bytes)?;
272 let meta_len = u32::from_le_bytes(meta_len_bytes) as usize;
273 let mut meta_bytes = vec![0u8; meta_len];
274 reader.read_exact(&mut meta_bytes)?;
275
276 let mut value_len_bytes = [0u8; 8];
278 reader.read_exact(&mut value_len_bytes)?;
279 let value_len = u64::from_le_bytes(value_len_bytes) as usize;
280 let mut value_bytes = vec![0u8; value_len];
281 reader.read_exact(&mut value_bytes)?;
282
283 let mut stored_checksum = [0u8; 32];
285 reader.read_exact(&mut stored_checksum)?;
286
287 let mut hasher = blake3::Hasher::new();
289 hasher.update(&key_bytes);
290 hasher.update(&meta_bytes);
291 hasher.update(&value_bytes);
292 let computed_checksum = *hasher.finalize().as_bytes();
293
294 if stored_checksum != computed_checksum {
295 return Err(QdbError::ChecksumMismatch("File corrupted".to_string()));
296 }
297
298 let key = deserialize_key(&key_bytes)?;
300 let metadata: EntryMetadata = serde_json::from_slice(&meta_bytes)?;
301 let value = deserialize_value(&value_bytes, metadata.entry_type)?;
302
303 Ok(Entry {
304 key,
305 value,
306 entry_type: metadata.entry_type,
307 created_at: metadata.created_at,
308 modified_at: metadata.modified_at,
309 version: metadata.version,
310 metadata: metadata.metadata,
311 checksum: Some(stored_checksum),
312 })
313 }
314}
315
316impl Backend for DiskBackend {
317 fn get(&self, key: &Key) -> Result<Option<Entry>> {
318 self.check_closed()?;
319 let key_bytes = key.to_bytes();
320 let index = self.index.read();
321
322 if let Some(path) = index.get(&key_bytes) {
323 Ok(Some(Self::read_entry_from_file(path)?))
324 } else {
325 Ok(None)
326 }
327 }
328
329 fn put(&self, entry: Entry) -> Result<()> {
330 self.check_closed()?;
331 let key_bytes = entry.key.to_bytes();
332 let filename = Self::key_to_filename(&entry.key);
333 let file_path = self.path.join(&filename);
334
335 let is_new = {
336 let index = self.index.read();
337 !index.contains_key(&key_bytes)
338 };
339
340 Self::write_entry_to_file(&file_path, &entry)?;
341
342 {
343 let mut index = self.index.write();
344 index.insert(key_bytes, file_path);
345 }
346
347 if is_new {
348 self.entry_count.fetch_add(1, Ordering::Relaxed);
349 }
350
351 Ok(())
352 }
353
354 fn delete(&self, key: &Key) -> Result<bool> {
355 self.check_closed()?;
356 let key_bytes = key.to_bytes();
357
358 let path = {
359 let mut index = self.index.write();
360 index.remove(&key_bytes)
361 };
362
363 if let Some(path) = path {
364 fs::remove_file(path)?;
365 self.entry_count.fetch_sub(1, Ordering::Relaxed);
366 Ok(true)
367 } else {
368 Ok(false)
369 }
370 }
371
372 fn exists(&self, key: &Key) -> Result<bool> {
373 self.check_closed()?;
374 let key_bytes = key.to_bytes();
375 let index = self.index.read();
376 Ok(index.contains_key(&key_bytes))
377 }
378
379 fn keys(&self) -> Result<Vec<Key>> {
380 self.check_closed()?;
381 let index = self.index.read();
382 let mut keys = Vec::with_capacity(index.len());
383
384 for path in index.values() {
385 if let Ok(entry) = Self::read_entry_from_file(path) {
386 keys.push(entry.key);
387 }
388 }
389
390 Ok(keys)
391 }
392
393 fn len(&self) -> Result<usize> {
394 self.check_closed()?;
395 Ok(self.entry_count.load(Ordering::Relaxed) as usize)
396 }
397
398 fn flush(&self) -> Result<()> {
399 self.check_closed()?;
400 Ok(()) }
402
403 fn close(&self) -> Result<()> {
404 self.closed.store(true, Ordering::Release);
405 Ok(())
406 }
407}
408
409pub struct QDB<B: Backend = MemoryBackend> {
415 backend: Arc<B>,
416 config: QdbConfig,
417 stats: QdbStats,
418}
419
420#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
422pub enum RadiationMode {
423 #[default]
425 Standard,
426 SpaceHardened,
428 MaxProtection,
430}
431
432#[derive(Debug, Clone)]
434pub struct QdbConfig {
435 pub default_bond_dimension: usize,
437 pub golay_enabled: bool,
439 pub truncation_threshold: f64,
441 pub max_entry_size: usize,
443 pub read_only: bool,
445 pub radiation_mode: RadiationMode,
447 pub triple_redundancy: bool,
449 pub post_quantum_signing: bool,
451}
452
453impl Default for QdbConfig {
454 fn default() -> Self {
455 Self {
456 default_bond_dimension: 64,
457 golay_enabled: true,
458 truncation_threshold: 1e-10,
459 max_entry_size: 1024 * 1024 * 100, read_only: false,
461 radiation_mode: RadiationMode::Standard,
462 triple_redundancy: false,
463 post_quantum_signing: false,
464 }
465 }
466}
467
468impl QdbConfig {
469 pub fn space_hardened() -> Self {
471 Self {
472 golay_enabled: true,
473 radiation_mode: RadiationMode::SpaceHardened,
474 triple_redundancy: true,
475 ..Default::default()
476 }
477 }
478
479 pub fn max_protection() -> Self {
481 Self {
482 golay_enabled: true,
483 radiation_mode: RadiationMode::MaxProtection,
484 triple_redundancy: true,
485 post_quantum_signing: true,
486 ..Default::default()
487 }
488 }
489}
490
491#[derive(Debug, Default)]
493pub struct QdbStats {
494 pub reads: AtomicU64,
495 pub writes: AtomicU64,
496 pub deletes: AtomicU64,
497 pub cache_hits: AtomicU64,
498 pub cache_misses: AtomicU64,
499}
500
501impl<B: Backend> QDB<B> {
502 pub fn new(backend: B) -> Self {
504 Self {
505 backend: Arc::new(backend),
506 config: QdbConfig::default(),
507 stats: QdbStats::default(),
508 }
509 }
510
511 pub fn with_config(backend: B, config: QdbConfig) -> Self {
513 Self {
514 backend: Arc::new(backend),
515 config,
516 stats: QdbStats::default(),
517 }
518 }
519
520 pub fn config(&self) -> &QdbConfig {
522 &self.config
523 }
524
525 pub fn stats(&self) -> &QdbStats {
527 &self.stats
528 }
529
530 pub fn backend(&self) -> &B {
532 &self.backend
533 }
534
535 pub fn get(&self, key: impl Into<Key>) -> Result<Option<Value>> {
541 self.stats.reads.fetch_add(1, Ordering::Relaxed);
542 let entry = self.backend.get(&key.into())?;
543 Ok(entry.map(|e| e.value))
544 }
545
546 pub fn get_entry(&self, key: impl Into<Key>) -> Result<Option<Entry>> {
548 self.stats.reads.fetch_add(1, Ordering::Relaxed);
549 self.backend.get(&key.into())
550 }
551
552 pub fn put(&self, key: impl Into<Key>, value: impl Into<Value>) -> Result<()> {
554 if self.config.read_only {
555 return Err(QdbError::ReadOnly);
556 }
557
558 self.stats.writes.fetch_add(1, Ordering::Relaxed);
559 let entry = Entry::new(key.into(), value.into());
560
561 if entry.size_bytes() > self.config.max_entry_size {
562 return Err(QdbError::CapacityExceeded(format!(
563 "Entry size {} exceeds maximum {}",
564 entry.size_bytes(),
565 self.config.max_entry_size
566 )));
567 }
568
569 self.backend.put(entry)
570 }
571
572 pub fn put_entry(&self, entry: Entry) -> Result<()> {
574 if self.config.read_only {
575 return Err(QdbError::ReadOnly);
576 }
577
578 self.stats.writes.fetch_add(1, Ordering::Relaxed);
579 self.backend.put(entry)
580 }
581
582 pub fn delete(&self, key: impl Into<Key>) -> Result<bool> {
584 if self.config.read_only {
585 return Err(QdbError::ReadOnly);
586 }
587
588 self.stats.deletes.fetch_add(1, Ordering::Relaxed);
589 self.backend.delete(&key.into())
590 }
591
592 pub fn exists(&self, key: impl Into<Key>) -> Result<bool> {
594 self.backend.exists(&key.into())
595 }
596
597 pub fn keys(&self) -> Result<Vec<Key>> {
599 self.backend.keys()
600 }
601
602 pub fn len(&self) -> Result<usize> {
604 self.backend.len()
605 }
606
607 pub fn is_empty(&self) -> Result<bool> {
609 self.backend.is_empty()
610 }
611
612 pub fn put_quantum(&self, key: impl Into<Key>, qft: QftFile) -> Result<()> {
618 if self.config.read_only {
619 return Err(QdbError::ReadOnly);
620 }
621
622 self.stats.writes.fetch_add(1, Ordering::Relaxed);
623 let entry = Entry::quantum(key.into(), qft);
624 self.backend.put(entry)
625 }
626
627 pub fn get_quantum(&self, key: impl Into<Key>) -> Result<Option<QftFile>> {
629 self.stats.reads.fetch_add(1, Ordering::Relaxed);
630 let entry = self.backend.get(&key.into())?;
631
632 match entry {
633 Some(e) => match e.value {
634 Value::Quantum(qft) => Ok(Some(*qft)),
635 _ => Err(QdbError::ValueError(
636 "Entry is not a quantum state".to_string(),
637 )),
638 },
639 None => Ok(None),
640 }
641 }
642
643 pub fn create_quantum_state(
645 &self,
646 key: impl Into<Key>,
647 num_qubits: usize,
648 ) -> Result<()> {
649 let qft = QftBuilder::new(num_qubits)
650 .bond_dimension(self.config.default_bond_dimension)
651 .golay(self.config.golay_enabled)
652 .truncation_threshold(self.config.truncation_threshold)
653 .build()?;
654
655 self.put_quantum(key, qft)
656 }
657
658 pub fn put_batch(&self, entries: Vec<Entry>) -> Result<()> {
664 if self.config.read_only {
665 return Err(QdbError::ReadOnly);
666 }
667
668 for entry in entries {
669 self.backend.put(entry)?;
670 self.stats.writes.fetch_add(1, Ordering::Relaxed);
671 }
672 Ok(())
673 }
674
675 pub fn get_batch(&self, keys: Vec<Key>) -> Result<Vec<Option<Value>>> {
677 let mut results = Vec::with_capacity(keys.len());
678 for key in keys {
679 self.stats.reads.fetch_add(1, Ordering::Relaxed);
680 let entry = self.backend.get(&key)?;
681 results.push(entry.map(|e| e.value));
682 }
683 Ok(results)
684 }
685
686 pub fn flush(&self) -> Result<()> {
692 self.backend.flush()
693 }
694
695 pub fn close(&self) -> Result<()> {
697 self.backend.close()
698 }
699}
700
701use serde::{Serialize, Deserialize};
706
707#[derive(Debug, Serialize, Deserialize)]
708struct EntryMetadata {
709 entry_type: crate::entry::EntryType,
710 created_at: u64,
711 modified_at: u64,
712 version: u64,
713 metadata: HashMap<String, String>,
714}
715
716fn deserialize_key(bytes: &[u8]) -> Result<Key> {
717 if bytes.is_empty() {
718 return Err(QdbError::InvalidKey("Empty key".to_string()));
719 }
720
721 match bytes[0] {
722 0 => Ok(Key::String(
723 String::from_utf8(bytes[1..].to_vec())
724 .map_err(|e| QdbError::InvalidKey(e.to_string()))?,
725 )),
726 1 => {
727 if bytes.len() < 9 {
728 return Err(QdbError::InvalidKey("Invalid integer key".to_string()));
729 }
730 let i = i64::from_le_bytes(bytes[1..9].try_into().unwrap());
731 Ok(Key::Integer(i))
732 }
733 2 => {
734 let mut parts = Vec::new();
735 let mut offset = 1;
736 while offset < bytes.len() {
737 if offset + 4 > bytes.len() {
738 break;
739 }
740 let part_len =
741 u32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap()) as usize;
742 offset += 4;
743 if offset + part_len > bytes.len() {
744 break;
745 }
746 let part = deserialize_key(&bytes[offset..offset + part_len])?;
747 parts.push(part);
748 offset += part_len;
749 }
750 Ok(Key::Composite(parts))
751 }
752 3 => Ok(Key::Binary(bytes[1..].to_vec())),
753 _ => Err(QdbError::InvalidKey(format!(
754 "Unknown key type: {}",
755 bytes[0]
756 ))),
757 }
758}
759
760fn deserialize_value(bytes: &[u8], entry_type: crate::entry::EntryType) -> Result<Value> {
761 match entry_type {
762 crate::entry::EntryType::QuantumState => {
763 let qft = QftFile::from_bytes(bytes)?;
764 Ok(Value::Quantum(Box::new(qft)))
765 }
766 _ => {
767 let value: Value = serde_json::from_slice(bytes)?;
768 Ok(value)
769 }
770 }
771}
772
773mod hex {
774 pub fn encode(data: &[u8]) -> String {
775 data.iter().map(|b| format!("{:02x}", b)).collect()
776 }
777}
778
779#[cfg(test)]
780mod tests {
781 use super::*;
782
783 #[test]
784 fn test_memory_backend() {
785 let backend = MemoryBackend::new();
786 let db = QDB::new(backend);
787
788 db.put("key1", "value1").unwrap();
789 assert!(db.exists("key1").unwrap());
790
791 let value = db.get("key1").unwrap();
792 assert!(matches!(value, Some(Value::String(s)) if s == "value1"));
793
794 db.delete("key1").unwrap();
795 assert!(!db.exists("key1").unwrap());
796 }
797
798 #[test]
799 fn test_quantum_storage() {
800 let backend = MemoryBackend::new();
801 let db = QDB::new(backend);
802
803 let qft = QftFile::new(4).unwrap();
804 db.put_quantum("quantum_state", qft).unwrap();
805
806 let loaded = db.get_quantum("quantum_state").unwrap().unwrap();
807 assert_eq!(loaded.num_qubits(), 4);
808 }
809
810 #[test]
811 fn test_batch_operations() {
812 let backend = MemoryBackend::new();
813 let db = QDB::new(backend);
814
815 let entries = vec![
816 Entry::new(Key::string("k1"), Value::Integer(1)),
817 Entry::new(Key::string("k2"), Value::Integer(2)),
818 Entry::new(Key::string("k3"), Value::Integer(3)),
819 ];
820
821 db.put_batch(entries).unwrap();
822 assert_eq!(db.len().unwrap(), 3);
823
824 let keys = vec![Key::string("k1"), Key::string("k2"), Key::string("k3")];
825 let values = db.get_batch(keys).unwrap();
826 assert_eq!(values.len(), 3);
827 }
828}