Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "kvspace-durable"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "可嵌入的 KVSpace(Rust),严格翻译 kvspace-go;后端 redis/fs/s3"
description = "可嵌入的 KVSpace(Rust),对齐 kvspace ABI 与线格式;后端 redis/fs/s3"

[lib]
name = "kvspace_durable"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Crate types: `rlib`, `staticlib`, `cdylib` (`libkvspace_durable.so`).

C ABI exported from the cdylib (`src/ffi.rs`):

- lifecycle: `kvspaceConnect`, `kvspaceClose`, `kvspaceDisconnect`
- lifecycle: `kvspaceConnect`, `kvspaceClose`
- KV read/write (zero-copy borrow model, no free): `kvspaceGet` (borrow), `kvspaceWriteInPlace`, `kvspaceWriteNewPlace`
- enumerate / delete / copy: `kvspaceListLen`, `kvspaceListAt`, `kvspaceDel`, `kvspaceDelTree`, `kvspaceCp`, `kvspaceCpTree`
- directories / extindex: `kvspaceMkindex`, `kvspaceMkindexExt`, `kvspaceRmindexExt`
Expand Down
11 changes: 2 additions & 9 deletions src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@

use std::time::Duration;

use crate::coord::{grow_coord_dims, is_coord};
use crate::kvspace::{KVPair, KVSpace};
use crate::kvspace_common::{
dir_exists, get_one, join_path, mk_index_recursive, sep_path, split_index, strip_dir_suf,
validate_ptr, watch_value,
join_path, mk_index_recursive, sep_path, split_index, strip_dir_suf, validate_ptr, watch_value,
};
use crate::r#const::*;
use crate::store::KVStore;
Expand All @@ -16,7 +14,7 @@ use crate::xvalue::{
};
use crate::xvalue_index::{
encode_ext_index_grow, encode_index_grow, grow_cap, matrix_cap, matrix_width, new_ext_index,
new_index, new_map_index,
new_index,
};

pub struct Backend<S: KVStore> {
Expand Down Expand Up @@ -64,7 +62,6 @@ impl<S: KVStore> Backend<S> {
}
}


// ── link 解析 ───────────────────────────────────────────────────

fn resolve_path(&self, path: &str) -> String {
Expand Down Expand Up @@ -916,8 +913,4 @@ impl<S: KVStore> KVSpace for Backend<S> {
self.store.flush();
Ok(())
}

fn dis_conn(&mut self) -> Result<(), String> {
Ok(())
}
}
20 changes: 3 additions & 17 deletions src/const.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// const.rs — 对齐 const.go
// 路径与成员分隔符统一管理。所有构造 KV 路径、解析限定名、成员访问的地方
// 均须使用这些常量,禁止硬编码 "·" 等裸字符串。
// const.rs — 路径/分隔符/错误消息/kind 常量。
// 所有构造 KV 路径、解析限定名、成员访问的地方均须使用这些常量,禁止硬编码 "·" 等裸字符串。

// ── 路径结构 ──────────────────────────────────────────────────────────────

Expand All @@ -10,30 +9,17 @@ pub const RUNTIME_MEMBER_SEP: &str = "‥"; // 运行时保留字段前缀(U+2
pub const INDEX_VALUE_SEP: &str = "\n"; // index XValueHead 中的路径分隔符
pub const EXT_INDEX_HEAD: &str = "…"; // extindex XValueHead bytes 首元素前缀,如 …/lib/init/

// ── 错误(对齐 const.go 的 error 变量) ──────────────────────────────────
// ── 错误消息 ────────────────────────────────────────────────────────────

pub const ERR_DIR_MUST_END_WITH_SLASH: &str = "kvspace: index must end with /";
pub const ERR_INVALID_PATH: &str = "kvspace: path must be absolute and canonical";
pub const ERR_INVALID_DIR_VALUE: &str = "kvspace: directory value must be kind=index";
pub const ERR_INVALID_VALUE: &str = "kvspace: value cannot be encoded and decoded losslessly";
pub const ERR_DISCONNECTED: &str = "kvspace: connection is disconnected";
pub const ERR_GET: &str = "kvspace: GET";
pub const ERR_PIPE_EXEC: &str = "kvspace: pipeline exec";
pub const ERR_RESOLVE: &str = "kvspace: 路径解析 GET";
pub const ERR_SCAN: &str = "kvspace: SCAN";
pub const ERR_EXT_WRITE: &str = "kvspace: 禁止对 extindex 只读路径执行写操作";
pub const ERR_EXT_DEL: &str = "kvspace: 禁止删除 extindex 只读路径";
pub const ERR_NOT_DIR: &str = "kvspace: 父路径不是目录";
pub const ERR_PARENT_NOT_FOUND: &str = "kvspace: 父目录不存在";
pub const ERR_EXT_CASCADE: &str = "kvspace: ExtIndex 不容许级联";
pub const ERR_EXT_TARGET: &str = "kvspace: ExtIndex target must be an existing ordinary index";
pub const ERR_EXT_COLLISION: &str = "kvspace: ExtIndex local and extension children overlap";
pub const ERR_LINK_TYPE_MISMATCH: &str = "kvspace: Link target 和 linkpath 类型不一致";
pub const ERR_MAP_NDIM: &str = "kvspace: stringkeymap 恒 ndim>=1,dims 不可为空";
pub const ERR_MAP_COORD: &str = "kvspace: stringkeymap 成员名必须是坐标段 [s0,s1,...]";
pub const ERR_MEMBER_NAME: &str = "kvspace: 命名成员名含非法字符";
pub const ERR_MEMHEAD_MISSING: &str = "kvspace: memhead 不存在,禁止写 memitem";
pub const ERR_LINK_PATH_EXISTS: &str = "kvspace: Link path already contains a non-link value";

// ── XValueHead kind ─────────────────────────────────────────────────────────

Expand Down
31 changes: 0 additions & 31 deletions src/coord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,6 @@ pub fn cmp_coord(a: &str, b: &str) -> Ordering {
}
}

/// 坐标是否落在 dims 内(维数相符且逐维小于)。
pub fn coord_in_dims(coords: &[i64], dims: &[i32]) -> bool {
coords.len() == dims.len()
&& coords
.iter()
.zip(dims)
.all(|(&c, &d)| c >= 0 && c < d as i64)
}

/// 一维 dims 至少容纳坐标 v(max(dims[0], v+1)),dims 为空时起算为 1。
pub fn grow_dim(dims: &[i32], v: i64) -> Vec<i32> {
if dims.is_empty() {
vec![v as i32 + 1]
} else {
vec![dims[0].max(v as i32 + 1)]
}
}

/// 一组坐标段的维数:逐段取最大整数坐标,dims 为空时按首个整数坐标段长度起算;
/// 无任何整数坐标(纯小数/字符串坐标)时退化为 1 维、长度为成员数。
pub fn grow_coord_dims(dims: &[i32], names: &[String]) -> Vec<i32> {
Expand All @@ -98,16 +80,3 @@ pub fn grow_coord_dims(dims: &[i32], names: &[String]) -> Vec<i32> {
}
d
}

/// 命名成员名字符约束:禁 / · [ ] \n \r \0 ‥ … 与 ASCII 控制字符,禁空串。
/// '.' 已放开(小数/含点字符串可作 key),成员分隔符改为 ·(OBJ_SEP)。
pub fn valid_member_name(name: &str) -> bool {
!name.is_empty()
&& !name.contains(crate::r#const::OBJ_SEP)
&& !name.chars().any(|c| {
matches!(
c,
'/' | '[' | ']' | '\n' | '\r' | '\0' | '\u{2025}' | '\u{2026}'
) || (c as u32) < 0x20
})
}
13 changes: 0 additions & 13 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use std::time::Duration;

use crate::conn::conn;
use crate::kvspace::{KVPair, KVSpace};
use crate::kvspace_common::get_one;
use crate::xvalue::{decode_xvalue, decode_xvalue_head, encode_head, encode_head_perm, new_ptr};
use crate::xvalue_bool::new_bool;
use crate::xvalue_byte::new_char_byte;
Expand Down Expand Up @@ -785,18 +784,6 @@ pub extern "C" fn kvspaceClear(h: *mut Handle, err: *mut c_char, err_cap: u32) -
result_to_code(catch_panic(|| kv.clear()), err, err_cap)
}

#[no_mangle]
pub extern "C" fn kvspaceDisconnect(h: *mut Handle, err: *mut c_char, err_cap: u32) -> c_int {
let kv: &mut dyn KVSpace = match unsafe { kv_flush(h) } {
Ok(k) => k,
Err(e) => {
write_err(err, err_cap, &e);
return 1;
}
};
result_to_code(catch_panic(|| kv.dis_conn()), err, err_cap)
}

// ── XValue 编解码(head/TLV + 标准标量构造器) ─────────────────────────

/// 通用 TLV 编码(内联,ref=0)。dims/ndim 直接落盘:ndim=0 标量,dims 可为 NULL。
Expand Down
35 changes: 3 additions & 32 deletions src/fs/kvspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ use std::os::unix::fs::FileExt;
use std::path::{Path, PathBuf};
use std::time::Duration;

use crate::coord::{cmp_coord, grow_coord_dims, is_coord, parse_coord};
use crate::coord::cmp_coord;
use crate::kvspace::{KVPair, KVSpace};
use crate::kvspace_common::{
join_path, sep_path, split_index, strip_dir_suf, validate_ptr, watch_value, SepKind,
join_path, sep_path, split_index, strip_dir_suf, validate_ptr, watch_value,
};
use crate::r#const::*;
use crate::xvalue::*;
use crate::xvalue_index::{new_ext_index, new_index, new_map_index};
use crate::xvalue_index::{new_ext_index, new_index};

const EXTINDEX_MARKER: &str = "__extindex__";
const SELF_MARKER: &str = "__self__";
Expand Down Expand Up @@ -61,18 +61,6 @@ impl FsKVSpace {
self.root.join(rel.trim_start_matches('/'))
}

/// fs 路径 → kvspace key:'·/' → '·'
fn key_of(&self, path: &Path) -> String {
let rel = path.strip_prefix(&self.root).unwrap_or(path);
let pat = [OBJ_SEP, "/"].concat();
let s = rel.to_string_lossy().replace(pat.as_str(), OBJ_SEP);
if s.is_empty() {
PATH_SEP.to_string()
} else {
format!("/{}", s)
}
}

fn is_dir_key(key: &str) -> bool {
key.ends_with(DIR_INDEX_SUF) || key.ends_with(OBJ_SEP)
}
Expand Down Expand Up @@ -143,14 +131,6 @@ impl FsKVSpace {
}
}

fn suffix_for(key: &str) -> &'static str {
if key.ends_with(OBJ_SEP) && !key.ends_with(DIR_INDEX_SUF) {
OBJ_SEP
} else {
DIR_INDEX_SUF
}
}

fn parent_name(path: &str) -> (String, String) {
let mut path = path.to_string();
if Self::is_dir_key(&path) && path != PATH_SEP {
Expand Down Expand Up @@ -710,13 +690,4 @@ impl KVSpace for FsKVSpace {
let _ = fs::create_dir_all(&self.root);
Ok(())
}

fn dis_conn(&mut self) -> Result<(), String> {
Ok(())
}
}

// 供测试用:返回 root 下的顶层条目数。
pub fn top_level_count(kv: &FsKVSpace) -> usize {
fs::read_dir(&kv.root).map(|d| d.count()).unwrap_or(0)
}
1 change: 0 additions & 1 deletion src/kvspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,4 @@ pub trait KVSpace {
fn del_ext_index(&mut self, path: &str) -> Result<(), String>;

fn clear(&mut self) -> Result<(), String>;
fn dis_conn(&mut self) -> Result<(), String>;
}
7 changes: 1 addition & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
#![allow(unused)]
#![allow(non_snake_case)]

// kvspace-durable — 严格翻译 kvspace-go。
// 文件对应:const.go → const.rs,xvalue*.go → xvalue*.rs,kvspace.go → kvspace.rs,
// kvspace_common.go → kvspace_common.rs,conn.go → conn.rs,redis/kvspace.go → backend.rs + redis/store.rs。
// kvspace-durable — 可嵌入的 KVSpace(Rust),对齐 kvspace ABI 与线格式。
// 后端:redis、fs(goheap/shm 不属本项目)。

pub mod r#const;
Expand Down
4 changes: 4 additions & 0 deletions src/redis/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,11 @@ impl RedisStore {
}

enum Resp {
// 字段 0 暂未被读取——Redis 错误文本当前被静默丢弃,待接入 Result 错误传播后启用(见 todo)
#[allow(dead_code)]
Simple(String),
// 同上
#[allow(dead_code)]
Error(String),
Integer(i64),
Bulk(Option<Vec<u8>>),
Expand Down
27 changes: 0 additions & 27 deletions src/xvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,33 +308,6 @@ impl XValue {
matches!(self, XValue::Ptr(_))
}

pub fn byte_len(&self) -> i32 {
match self {
XValue::None => 0,
XValue::Ptr(p) => p.target.len() as i32,
XValue::Bool(d) => d.data.len() as i32,
XValue::Int8(d) => d.data.len() as i32,
XValue::Int16(d) => (d.data.len() * 2) as i32,
XValue::Int32(d) => (d.data.len() * 4) as i32,
XValue::Int64(d) => (d.data.len() * 8) as i32,
XValue::Uint8(d) => d.data.len() as i32,
XValue::Uint16(d) => (d.data.len() * 2) as i32,
XValue::Uint32(d) => (d.data.len() * 4) as i32,
XValue::Uint64(d) => (d.data.len() * 8) as i32,
XValue::Float32(d) => (d.data.len() * 4) as i32,
XValue::Float64(d) => (d.data.len() * 8) as i32,
XValue::CharByte(d) => d.data.len() as i32,
XValue::CharAscii(d) => d.data.len() as i32,
XValue::Char32(d) => (d.data.len() * 4) as i32,
XValue::Map(_) => 1,
XValue::Index(d) => crate::xvalue_index::encode_index(d).1.len() as i32,
XValue::ExtIndex(e) => crate::xvalue_index::encode_ext_index(&e.ext_path, &e.childs)
.1
.len() as i32,
XValue::Opaque(o) => o.body.len() as i32,
}
}

pub fn array_len(&self) -> i32 {
match self {
XValue::None => 0,
Expand Down
6 changes: 0 additions & 6 deletions src/xvalue_byte.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ pub fn new_char_byte(v: &[u8]) -> XValue {
dims: char_dims(v.len()),
})
}
pub fn new_char_ascii(v: &[u8]) -> XValue {
XValue::CharAscii(Arr {
data: v.to_vec(),
dims: char_dims(v.len()),
})
}
pub fn new_char32(v: &[u32]) -> XValue {
XValue::Char32(Arr {
data: v.to_vec(),
Expand Down
18 changes: 0 additions & 18 deletions src/xvalue_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,6 @@
use crate::r#const::*;
use crate::xvalue::{dims_from_len, encode_head, Arr, XValue};

pub fn new_int8(v: &[i8]) -> XValue {
XValue::Int8(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
pub fn new_int16(v: &[i16]) -> XValue {
XValue::Int16(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
pub fn new_int32(v: &[i32]) -> XValue {
XValue::Int32(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
pub fn new_int64(v: &[i64]) -> XValue {
XValue::Int64(Arr {
data: v.to_vec(),
Expand Down
27 changes: 1 addition & 26 deletions src/xvalue_uint.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,7 @@
// xvalue_uint.rs — 对齐 xvalue_uint.go

use crate::r#const::*;
use crate::xvalue::{dims_from_len, encode_head, Arr, XValue};

pub fn new_uint8(v: &[u8]) -> XValue {
XValue::Uint8(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
pub fn new_uint16(v: &[u16]) -> XValue {
XValue::Uint16(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
pub fn new_uint32(v: &[u32]) -> XValue {
XValue::Uint32(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
pub fn new_uint64(v: &[u64]) -> XValue {
XValue::Uint64(Arr {
data: v.to_vec(),
dims: dims_from_len(v.len()),
})
}
use crate::xvalue::{encode_head, Arr};

pub fn decode_uint8(body: &[u8], dims: &[i32]) -> Arr<u8> {
Arr {
Expand Down
Loading