Skip to content

Commit 0c3728b

Browse files
Merge pull request #202 from JakeRoggenbuck/abort-commit-record-level
record lock approach
2 parents 5f240b5 + 973ba2f commit 0c3728b

File tree

6 files changed

+888
-140
lines changed

6 files changed

+888
-140
lines changed

benches/merge_benchmarks.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
22
use redoxql::pagerange::PageRange;
3-
use redoxql::record::{Record, RecordAddress};
3+
use redoxql::record::{Record, RecordAddress, RecordLock};
44
use redoxql::table::PageDirectory;
5-
use std::sync::{Arc, Mutex};
5+
use std::sync::{Arc, Mutex, RwLock};
66
use std::time::Duration;
77

88
fn setup_benchmark_data(
@@ -28,6 +28,7 @@ fn setup_benchmark_data(
2828
let record = Record {
2929
rid,
3030
addresses: Arc::new(Mutex::new(addresses)),
31+
lock: Arc::new(RwLock::new(RecordLock::default())),
3132
};
3233

3334
pd.directory.insert(rid, record);
@@ -45,6 +46,7 @@ fn setup_benchmark_data(
4546
let record = Record {
4647
rid,
4748
addresses: Arc::new(Mutex::new(addresses)),
49+
lock: Arc::new(RwLock::new(RecordLock::default())),
4850
};
4951

5052
pd.directory.insert(rid, record);

src/container.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use crate::record::RecordLock;
2+
13
use super::filewriter::{build_binary_writer, Writer};
24
use super::page::PhysicalPage;
35
use super::record::{Record, RecordAddress};
46
use serde::{Deserialize, Serialize};
5-
use std::sync::{Arc, Mutex};
7+
use std::sync::{Arc, Mutex, RwLock};
68

79
#[derive(Clone, Default, Deserialize, Serialize, Debug)]
810
pub struct BaseContainerMetadata {
@@ -191,6 +193,7 @@ impl BaseContainer {
191193
Record {
192194
rid,
193195
addresses: addresses.clone(),
196+
lock: Arc::new(RwLock::new(RecordLock::default())),
194197
}
195198
}
196199

@@ -483,6 +486,7 @@ impl TailContainer {
483486
Record {
484487
rid,
485488
addresses: addresses.clone(),
489+
lock: Arc::new(RwLock::new(RecordLock::default())),
486490
}
487491
}
488492

src/database.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ pub struct RDatabaseMetadata {
2121
db_filepath: Option<String>,
2222
}
2323

24+
// Define lock types for 2PL
25+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26+
pub enum LockType {
27+
Shared, // Read lock (S)
28+
Exclusive, // Write lock (X)
29+
}
30+
31+
impl std::fmt::Display for LockType {
32+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33+
match self {
34+
LockType::Shared => write!(f, "Shared"),
35+
LockType::Exclusive => write!(f, "Exclusive"),
36+
}
37+
}
38+
}
39+
40+
// A unique identifier for a record: (RTableHandle, record_id, lock_type)
41+
pub type RecordId = (RTableHandle, i64, LockType);
42+
pub type RecordId2 = (String, i64, LockType);
43+
2444
#[pyclass]
2545
pub struct RDatabase {
2646
/// This is where we keep all of the tables
@@ -157,14 +177,6 @@ impl RDatabase {
157177
index_guard.set_owner(Arc::downgrade(&arc_table));
158178
}
159179

160-
// PREVIOUS IMPLEMENTATION
161-
// let i = self.tables.len();
162-
163-
// Map a name of a table to it's index on the self.tables field
164-
// self.tables_hashmap.insert(name, i);
165-
166-
// self.tables.push(t);
167-
168180
// Push t into the tables vector so its address becomes stable.
169181
self.tables.push(arc_table.clone());
170182
let i = self.tables.len() - 1;

src/pagerange.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use super::container::{
33
};
44
use super::filewriter::{build_binary_writer, Writer};
55
use super::record::Record;
6-
use crate::record::RecordAddress;
6+
use crate::record::{RecordAddress, RecordLock};
77
use crate::table::PageDirectory;
88
use log::info;
99
use serde::{Deserialize, Serialize};
1010
use std::collections::HashSet;
11-
use std::sync::{Arc, Mutex};
11+
use std::sync::{Arc, Mutex, RwLock};
1212
use std::thread;
1313

1414
#[derive(Clone, Default, Deserialize, Serialize, Debug)]
@@ -136,6 +136,7 @@ impl PageRange {
136136
let new_record = Record {
137137
rid: base_rid,
138138
addresses: Arc::new(Mutex::new(Vec::new())),
139+
lock: Arc::new(RwLock::new(RecordLock::default())),
139140
};
140141

141142
{
@@ -345,6 +346,7 @@ impl PageRange {
345346
let new_record = Record {
346347
rid: base_rid,
347348
addresses: Arc::new(Mutex::new(Vec::new())),
349+
lock: Arc::new(RwLock::new(RecordLock::default())),
348350
};
349351

350352
{

src/record.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::container::{ReservedColumns, NUM_RESERVED_COLUMNS};
33
use pyo3::prelude::*;
44
use rustc_hash::FxHashMap;
55
use serde::{Deserialize, Serialize};
6-
use std::sync::{Arc, Mutex};
6+
use std::sync::{Arc, Mutex, RwLock};
77

88
type RedoxQLHashMap<K, V> = FxHashMap<K, V>;
99

@@ -89,6 +89,7 @@ impl RecordMetadata {
8989
Record {
9090
rid: self.rid,
9191
addresses: Arc::new(Mutex::new(rec_addrs)),
92+
lock: Arc::new(RwLock::new(RecordLock::default())),
9293
}
9394
}
9495
}
@@ -102,6 +103,14 @@ pub struct Record {
102103
/// The Record keeps a Vector of the RecordAddress, which allow us to actually call
103104
/// RecordAddress.page.read() to get the value stored at the page using the offset
104105
pub addresses: Arc<Mutex<Vec<RecordAddress>>>,
106+
107+
pub lock: Arc<RwLock<RecordLock>>,
108+
}
109+
110+
#[derive(Debug, Clone, Default)]
111+
pub struct RecordLock {
112+
pub reader_count: i64,
113+
pub writer_count: i64,
105114
}
106115

107116
impl Record {
@@ -121,6 +130,48 @@ impl Record {
121130

122131
return rm;
123132
}
133+
134+
pub fn attempt_obtain_read(&self) -> bool {
135+
let mut a = self.lock.write().unwrap();
136+
137+
if a.writer_count != 0 {
138+
return false;
139+
}
140+
141+
a.reader_count += 1;
142+
143+
true
144+
}
145+
146+
pub fn attempt_obtain_write(&self) -> bool {
147+
let mut a = self.lock.write().unwrap();
148+
149+
if a.writer_count != 0 || a.reader_count != 0 {
150+
return false;
151+
}
152+
153+
a.writer_count += 1;
154+
155+
true
156+
}
157+
158+
pub fn release_read_lock(&self) {
159+
let mut a = self.lock.write().unwrap();
160+
a.reader_count -= 1;
161+
162+
if a.reader_count < 0 {
163+
panic!("write_count less than 0, rid {}", self.rid)
164+
}
165+
}
166+
167+
pub fn release_write_lock(&self) {
168+
let mut a = self.lock.write().unwrap();
169+
a.writer_count -= 1;
170+
171+
if a.writer_count < 0 {
172+
panic!("write_count less than 0, rid {}", self.rid)
173+
}
174+
}
124175
}
125176

126177
#[pymethods]

0 commit comments

Comments
 (0)