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;