1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
//! Minimal schema-less database management system with ACID guaranties.
//!
//! # Examples
//!
//! ```
//! use db_core::instance::Instance;
//! use db_core::FileState;
//! use db_core::FileType;
//! use db_core::FileDesc;
//! use db_core::instance::Read;
//! use db_core::instance::Write;
//! use db_core::config::ConfigMt;
//! use std::path::Path;
//!
//!
//! //
//! // Database initialization (this is one-time action).
//! //
//!
//!
//! // Block size for the database.
//! let block_size = 8192;
//!
//!
//! // Create an empty directory for the database files.
//! let dspath = "/tmp/db-core-test-db";
//! if Path::new(dspath).exists() {
//! std::fs::remove_dir_all(dspath).expect("Failed to delete test dir on cleanup");
//! }
//! std::fs::create_dir(dspath).expect("Failed to create test dir");
//!
//! // Transaction log directory.
//! let log_dir = "/tmp/db-core-test-tranlog";
//! if Path::new(log_dir).exists() {
//! std::fs::remove_dir_all(log_dir).expect("Failed to delete test dir on cleanup");
//! }
//! std::fs::create_dir(log_dir).expect("Failed to create test dir");
//!
//!
//! // Define initial database files. There should be at least one file of each type (data store,
//! // versioning store, checkpont store).
//! let mut fdset = vec![];
//! let desc1 = FileDesc {
//! state: FileState::InUse,
//! file_id: 3,
//! extent_size: 16,
//! extent_num: 3,
//! max_extent_num: 65500,
//! file_type: FileType::DataStoreFile,
//! };
//! let desc2 = FileDesc {
//! state: FileState::InUse,
//! file_id: 4,
//! extent_size: 10,
//! extent_num: 3,
//! max_extent_num: 65500,
//! file_type: FileType::VersioningStoreFile,
//! };
//! let desc3 = FileDesc {
//! state: FileState::InUse,
//! file_id: 5,
//! extent_size: 10,
//! extent_num: 3,
//! max_extent_num: 65500,
//! file_type: FileType::CheckpointStoreFile,
//! };
//!
//! fdset.push(desc1);
//! fdset.push(desc2);
//! fdset.push(desc3);
//!
//! // Create a database.
//! Instance::initialize_datastore(dspath, block_size, &fdset).expect("Failed to init datastore");
//!
//!
//! //
//! // Startup and termination, transaction management, read and write data.
//! //
//!
//!
//! // Some random data.
//! let data = b"Hello, world!";
//!
//!
//! // Prepare configuration.
//! let conf = ConfigMt::new();
//! let mut c = conf.get_conf();
//! c.set_log_dir(log_dir.to_owned());
//! c.set_datastore_path(dspath.to_owned());
//! drop(c);
//!
//! // Start instance and open existing database.
//! let instance = Instance::new(conf.clone()).expect("Failed to create instance");
//!
//! // Begin transaction.
//! let mut trn = instance.begin_transaction().expect("Failed to begin transaction");
//!
//! // Create a new object.
//! let file_id = 3;
//! let mut obj = instance.open_create(file_id, &mut trn, data.len()).expect("Failed to create object");
//! let obj_id = obj.get_id();
//!
//! // Write some data.
//! obj.write_next(data).expect("Failed to write");
//! drop(obj);
//!
//! // Commit transaction.
//! instance.commit(trn).expect("Failed to commit");
//!
//! // Begin transaction.
//! let mut trn = instance.begin_transaction().expect("Failed to begin transaction");
//!
//! // Open object for reading and read some data.
//! let mut obj = instance.open_read(&obj_id, &trn).expect("Failed to open for reading");
//! let mut read_buf = vec![0u8;data.len()];
//! let mut read = 0;
//! let len = read_buf.len();
//! while read < len {
//! let r = obj.read_next(&mut read_buf[read..len]).expect("Failed to read");
//! if r == 0 {break;}
//! read += r;
//! }
//! assert_eq!(read_buf, data);
//! drop(obj);
//!
//! // Delete object (if object is in use wait for other transaction to finish for 1 second).
//! let wait_lock_ms = 1000;
//! instance.delete(&obj_id, &mut trn, wait_lock_ms).expect("Failed to delete object");
//!
//! // Rollback transaction.
//! instance.rollback(trn).expect("Failed to rollback");
//!
//! // Spawn another instance in a different thread.
//! let ss = instance.get_shared_state().expect("Failed to get shared state");
//!
//! let th = std::thread::spawn(move || {
//! let instance2 = Instance::from_shared_state(ss).expect("Failed to create instance");
//! // ...
//! instance2.terminate();
//! });
//!
//! // Add a database file.
//! let new_file_id = instance.add_datafile(FileType::DataStoreFile, 1000, 10, 1000).expect("Failed to add data file");
//!
//! // Terminate instance.
//! instance.terminate();
//!
//! ```
//!
//! ### Notes.
//!
//! 1. Block size is defined at the moment of database creation and can't be changed later.
//! 2. Each `file_id` must be unique. `file_id` 0, 1, and 2 are reserved and can't be used.
//!
mod buf_mgr;
mod common;
mod log_mgr;
mod storage;
mod system;
mod tran_mgr;
mod block_mgr;
pub use system::config;
pub use system::instance;
pub use common::errors;
pub use common::defs::ObjectId;
pub use common::defs::SeekFrom;
pub use storage::datastore::FileState;
pub use storage::datastore::FileType;
pub use storage::datastore::FileDesc;