Skip to content

Commit 03bf8e8

Browse files
committed
Add support for info,is_write_map,is_read_write,is_read_only
1 parent eae8b28 commit 03bf8e8

File tree

8 files changed

+158
-299
lines changed

8 files changed

+158
-299
lines changed

Cargo.lock

+7-282
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/mdbx-remote/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ rand_xorshift = "0.3"
4848
tempfile.workspace = true
4949
paste.workspace = true
5050
futures-util.workspace =true
51-
console-subscriber = "0.4"
51+
# console-subscriber = "0.4"
5252
# [[bench]]
5353
# name = "cursor"
5454
# harness = false

crates/mdbx-remote/mdbx-sys/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ fn generate_bindings(mdbx: &Path, out_file: &Path) {
9797
}
9898

9999
fn add_derives(&self, _info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec<String> {
100-
let serde_list = &["MDBX_commit_latency", "MDBX_stat"];
100+
let serde_list = &["MDBX_commit_latency", "MDBX_stat", "MDBX_envinfo"];
101101

102102
for candidate in serde_list.iter() {
103103
if _info.name.starts_with(candidate) {

crates/mdbx-remote/src/any.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ use tokio_stream::Stream;
88
use crate::{
99
remote::{ClientError, RemoteCursor, RemoteDatabase, RemoteEnvironment, RemoteTransaction},
1010
service::RemoteMDBXClient,
11-
CommitLatency, Cursor, Database, DatabaseFlags, Environment, EnvironmentFlags, Mode, Stat,
12-
TableObject, Transaction, TransactionKind, WriteFlags, RO, RW,
11+
CommitLatency, Cursor, Database, DatabaseFlags, Environment, EnvironmentFlags, EnvironmentKind,
12+
Info, Mode, Stat, TableObject, Transaction, TransactionKind, WriteFlags, RO, RW,
1313
};
1414

1515
type Result<T> = std::result::Result<T, ClientError>;
@@ -154,6 +154,32 @@ impl EnvironmentAny {
154154
Self::Remote(env) => Ok(env.stat().await?),
155155
}
156156
}
157+
158+
pub async fn info(&self) -> Result<Info> {
159+
match self {
160+
Self::Local(env) => Ok(env.info()?),
161+
Self::Remote(env) => Ok(env.info().await?),
162+
}
163+
}
164+
165+
pub fn env_kind(&self) -> EnvironmentKind {
166+
match self {
167+
Self::Local(env) => env.env_kind(),
168+
Self::Remote(env) => env.env_kind(),
169+
}
170+
}
171+
172+
pub fn is_write_map(&self) -> bool {
173+
self.env_kind().is_write_map()
174+
}
175+
176+
pub async fn is_read_write(&self) -> Result<bool> {
177+
Ok(!self.is_read_only().await?)
178+
}
179+
180+
pub async fn is_read_only(&self) -> Result<bool> {
181+
Ok(matches!(self.info().await?.mode(), Mode::ReadOnly))
182+
}
157183
}
158184

159185
#[derive(Debug)]

crates/mdbx-remote/src/environment.rs

+41-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
flags::EnvironmentFlags,
55
transaction::{RO, RW},
66
txn_manager::{TxnManager, TxnManagerMessage, TxnPtr},
7-
Transaction, TransactionKind,
7+
Mode, SyncMode, Transaction, TransactionKind,
88
};
99
use byteorder::{ByteOrder, NativeEndian};
1010
use mem::size_of;
@@ -73,14 +73,14 @@ impl Environment {
7373

7474
/// Returns true if the environment was opened in [`crate::Mode::ReadWrite`] mode.
7575
#[inline]
76-
pub fn is_read_write(&self) -> bool {
77-
self.inner.env_kind.is_write_map()
76+
pub fn is_read_write(&self) -> Result<bool> {
77+
Ok(!self.is_read_only()?)
7878
}
7979

8080
/// Returns true if the environment was opened in [`crate::Mode::ReadOnly`] mode.
8181
#[inline]
82-
pub fn is_read_only(&self) -> bool {
83-
!self.inner.env_kind.is_write_map()
82+
pub fn is_read_only(&self) -> Result<bool> {
83+
Ok(matches!(self.info()?.mode(), Mode::ReadOnly))
8484
}
8585

8686
/// Returns the transaction manager.
@@ -372,7 +372,7 @@ impl GeometryInfo {
372372
/// Environment information.
373373
///
374374
/// Contains environment information about the map size, readers, last txn id etc.
375-
#[derive(Debug)]
375+
#[derive(Debug, Serialize, Deserialize)]
376376
#[repr(transparent)]
377377
pub struct Info(ffi::MDBX_envinfo);
378378

@@ -381,6 +381,35 @@ impl Info {
381381
GeometryInfo(self.0.mi_geo)
382382
}
383383

384+
pub const fn mode(&self) -> Mode {
385+
let mode = self.0.mi_mode;
386+
if (mode & ffi::MDBX_RDONLY) != 0 {
387+
Mode::ReadOnly
388+
} else {
389+
if (mode & ffi::MDBX_SYNC_DURABLE) != 0 {
390+
Mode::ReadWrite {
391+
sync_mode: SyncMode::Durable,
392+
}
393+
} else if (mode & ffi::MDBX_UTTERLY_NOSYNC) != 0 {
394+
Mode::ReadWrite {
395+
sync_mode: SyncMode::UtterlyNoSync,
396+
}
397+
} else if (mode & ffi::MDBX_NOMETASYNC) != 0 {
398+
Mode::ReadWrite {
399+
sync_mode: SyncMode::NoMetaSync,
400+
}
401+
} else if (mode & ffi::MDBX_SAFE_NOSYNC) != 0 {
402+
Mode::ReadWrite {
403+
sync_mode: SyncMode::SafeNoSync,
404+
}
405+
} else {
406+
Mode::ReadWrite {
407+
sync_mode: SyncMode::Durable,
408+
}
409+
}
410+
}
411+
}
412+
384413
/// Size of memory map.
385414
#[inline]
386415
pub const fn map_size(&self) -> usize {
@@ -620,6 +649,12 @@ impl From<EnvironmentBuilder> for RemoteEnvironmentConfig {
620649
}
621650
}
622651

652+
impl RemoteEnvironmentConfig {
653+
pub(crate) fn env_kind(&self) -> EnvironmentKind {
654+
self.kind
655+
}
656+
}
657+
623658
impl From<RemoteEnvironmentConfig> for EnvironmentBuilder {
624659
fn from(value: RemoteEnvironmentConfig) -> Self {
625660
Self {

crates/mdbx-remote/src/remote.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use tokio_stream::Stream;
2525
use crate::{
2626
environment::RemoteEnvironmentConfig,
2727
service::{RemoteMDBXClient, ServerError},
28-
CommitLatency, DatabaseFlags, EnvironmentBuilder, Stat, TableObject, TransactionKind,
29-
WriteFlags, RO, RW,
28+
CommitLatency, DatabaseFlags, EnvironmentBuilder, EnvironmentKind, Info, Mode, Stat,
29+
TableObject, TransactionKind, WriteFlags, RO, RW,
3030
};
3131

3232
macro_rules! mdbx_try_optional {
@@ -111,6 +111,7 @@ pub(crate) struct RemoteEnvironmentInner {
111111
handle: u64,
112112
cl: RemoteMDBXClient,
113113
deadline: Duration,
114+
kind: EnvironmentKind,
114115
ch: oneshot::Sender<()>,
115116
}
116117

@@ -144,13 +145,15 @@ impl RemoteEnvironmentInner {
144145
tracing::debug!("Dispatcher dies");
145146
});
146147
let remote = RemoteEnvironmentConfig::from(builder);
148+
let kind = remote.env_kind();
147149
let handle = client
148150
.open_env(context_deadline(deadline), path, remote)
149151
.await??;
150152
Ok(Self {
151153
handle: handle,
152154
cl: client,
153155
deadline: deadline,
156+
kind: kind,
154157
ch: tx,
155158
})
156159
}
@@ -237,6 +240,30 @@ impl RemoteEnvironment {
237240
.env_stat(self.inner.context(), self.inner.handle)
238241
.await??)
239242
}
243+
244+
pub async fn info(&self) -> Result<Info> {
245+
Ok(self
246+
.inner
247+
.cl
248+
.env_info(self.inner.context(), self.inner.handle)
249+
.await??)
250+
}
251+
252+
pub fn env_kind(&self) -> EnvironmentKind {
253+
self.inner.kind
254+
}
255+
256+
pub fn is_write_map(&self) -> bool {
257+
self.inner.kind.is_write_map()
258+
}
259+
260+
pub async fn is_read_write(&self) -> Result<bool> {
261+
Ok(!self.is_read_only().await?)
262+
}
263+
264+
pub async fn is_read_only(&self) -> Result<bool> {
265+
Ok(matches!(self.info().await?.mode(), Mode::ReadOnly))
266+
}
240267
}
241268

242269
#[derive(Debug, Clone)]

crates/mdbx-remote/src/service.rs

+30-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use tokio::sync::RwLock;
66

77
use crate::{
88
environment::RemoteEnvironmentConfig, CommitLatency, Cursor, DatabaseFlags, Environment,
9-
EnvironmentBuilder, Stat, Transaction, TransactionKind, WriteFlags, RO, RW,
9+
EnvironmentBuilder, Info, Stat, Transaction, TransactionKind, WriteFlags, RO, RW,
1010
};
1111

1212
#[tarpc::service]
@@ -18,6 +18,7 @@ pub trait RemoteMDBX {
1818
async fn env_sync(env: u64, force: bool) -> Result<bool, ServerError>;
1919
async fn env_close(env: u64) -> Result<(), ServerError>;
2020
async fn env_stat(env: u64) -> Result<Stat, ServerError>;
21+
async fn env_info(env: u64) -> Result<Info, ServerError>;
2122

2223
async fn tx_create_db(
2324
env: u64,
@@ -230,7 +231,26 @@ impl RemoteMDBX for RemoteMDBXServer {
230231
.ok_or(ServerError::NOENV)?
231232
.env
232233
.clone();
233-
let ret = tokio::task::spawn_blocking(move || env.stat()).await??;
234+
let ret = env.stat()?;
235+
236+
Ok(ret)
237+
}
238+
239+
async fn env_info(
240+
self,
241+
_context: tarpc::context::Context,
242+
env: u64,
243+
) -> Result<Info, ServerError> {
244+
let env = self
245+
.state
246+
.read()
247+
.await
248+
.envs
249+
.get(&env)
250+
.ok_or(ServerError::NOENV)?
251+
.env
252+
.clone();
253+
let ret = env.info()?;
234254

235255
Ok(ret)
236256
}
@@ -250,6 +270,7 @@ impl RemoteMDBX for RemoteMDBXServer {
250270
.ok_or(ServerError::NOENV)?
251271
.env
252272
.clone();
273+
// This can block for a very time, though not forever
253274
let ret = tokio::task::spawn_blocking(move || env.sync(force)).await??;
254275

255276
Ok(ret)
@@ -344,7 +365,8 @@ impl RemoteMDBX for RemoteMDBXServer {
344365
if flags.contains(DatabaseFlags::CREATE) {
345366
return Err(ServerError::NOWRITABLE);
346367
}
347-
// This can block
368+
// This can block? can it?
369+
// But anyway opening databases should be not so frequent so overhead should be acceptable.
348370
tokio::task::spawn_blocking(move || tx.open_db(db.as_deref())).await??
349371
} else {
350372
return Err(ServerError::NOTX);
@@ -440,6 +462,7 @@ impl RemoteMDBX for RemoteMDBXServer {
440462
env.rwtxs.remove(&tx).ok_or(ServerError::NOTX)?
441463
};
442464

465+
// This can be slow, wrap it in spawn_blocking
443466
Ok(tokio::task::spawn_blocking(move || tx.tx.commit()).await??)
444467
}
445468

@@ -487,6 +510,7 @@ impl RemoteMDBX for RemoteMDBXServer {
487510
.tx
488511
.clone();
489512

513+
// Can this block forever? Anyway, wrap it with spawn_blocking for safety.
490514
let new_tx = tokio::task::spawn_blocking(move || tx.begin_nested_txn()).await??;
491515

492516
let mut lg = self.state.write().await;
@@ -518,11 +542,11 @@ impl RemoteMDBX for RemoteMDBXServer {
518542
let stat = if let Some(rw) = env.rwtxs.get(&tx) {
519543
let tx = rw.tx.clone();
520544
drop(lg);
521-
tokio::task::spawn_blocking(move || tx.db_stat_with_dbi(dbi)).await??
545+
tx.db_stat_with_dbi(dbi)?
522546
} else if let Some(ro) = env.rotxs.get(&tx) {
523547
let tx = ro.tx.clone();
524548
drop(lg);
525-
tokio::task::spawn_blocking(move || tx.db_stat_with_dbi(dbi)).await??
549+
tx.db_stat_with_dbi(dbi)?
526550
} else {
527551
return Err(ServerError::NOTX);
528552
};
@@ -550,6 +574,7 @@ impl RemoteMDBX for RemoteMDBXServer {
550574
.tx
551575
.clone();
552576

577+
// This can be slow
553578
tokio::task::spawn_blocking(move || tx.clear_db(dbi)).await??;
554579
Ok(())
555580
}

crates/mdbx-remote/tests/environment.rs

+21
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,27 @@ fn test_info() {
159159
// assert_eq!(info.last_pgno(), 1);
160160
// assert_eq!(info.last_txnid(), 0);
161161
assert_eq!(info.num_readers(), 0);
162+
assert!(matches!(
163+
info.mode(),
164+
Mode::ReadWrite {
165+
sync_mode: SyncMode::Durable
166+
}
167+
));
168+
169+
drop(env);
170+
let env = Environment::builder()
171+
.set_geometry(Geometry {
172+
size: Some(map_size..),
173+
..Default::default()
174+
})
175+
.set_flags(EnvironmentFlags {
176+
mode: Mode::ReadOnly,
177+
..Default::default()
178+
})
179+
.open(dir.path())
180+
.unwrap();
181+
let info = env.info().unwrap();
182+
assert!(matches!(info.mode(), Mode::ReadOnly));
162183
}
163184

164185
#[test]

0 commit comments

Comments
 (0)