3个版本

2.0.0-beta.42020年7月31日
2.0.0-beta.32020年7月3日
2.0.0-beta.22020年6月30日

#2839 in 数据库接口

Apache-2.0

99KB
1K SLoC

Turing·DB

Turing·DB Logo

TuringDB是一个用Rust编写的数据库,旨在实现分布式和水平扩展。它旨在替代不需要关系数据库或模式的情况。

数据库由Sled键值存储支持

动机

构建这个数据库的动机是拥有一个具有ACID属性、速度、类型安全、无轮询的change feeds、多集群查询和复制的键值数据库。Rust在速度、类型安全和编译时检查方面最有资格。此外,sled.rs已经被用作这个数据库的嵌入式键值存储,因为它是无锁的、有完全原子的操作、零拷贝读取、SSD优化的日志存储,并且是用Rust编写的,因此继承了语言的所有美好特性。

特性

数据库旨在成为

  1. 非常简单的文档数据库
  2. 具有查找和范围能力
  3. 分区容错和一致
  4. 提供无轮询的实时推送能力,灵感来自RethinkDB的change feeds
  5. 提供简单的连接
  6. 提供由Raft共识算法支持的可选分布式能力
  7. 提供可选的多集群查询
  8. 足够小,可以用作嵌入式数据库
  9. 足够小和快,可以用于嵌入式设备或大型服务器
  10. 非常有趣使用

正在开发中的特性包括

  1. 复制
  2. 多集群查询
  3. 无轮询的change feeds,灵感来自RethinkDB
  4. 支持JSON

服务器使用

  1. 从crates-io安装

    $ cargo install turingdb-server
    
  2. 启动服务器

    $ turingdb-server
    
  3. 创建一个新的cargo仓库

    $ cargo new my-app
    
  4. 编辑Cargo.toml文件

    #[dependencies]
    turingdb-helpers = #add the latest version here
    bincode = #add the latest version
    async-std = #add latest version here
    anyhow = # add latest version
    custom_codes = #add latest vesion
    

    或者,如果您已经安装了cargo-edit,可以使用它而不是手动添加依赖项

    $ cargo add turingdb-helpers bincode async-std anyhow custom_codes
    
  5. 在编辑器中打开src/main.rs文件

    use async_std::net::TcpStream;
    use async_std::io::prelude::*;
    use serde::{Serialize, Deserialize};
    use custom_codes::DbOps;
    
    const BUFFER_CAPACITY: usize = 64 * 1024; //16Kb
    const BUFFER_DATA_CAPACITY: usize = 1024 * 1024 * 16; // Db cannot hold data more than 16MB in size
    
    #[derive(Debug, Serialize, Deserialize)]
    struct DocumentQuery {
        db: String,
        document: Option<String>,
    }
    
    #[derive(Debug, Serialize, Deserialize)]
    pub (crate) struct FieldQuery {
        db: String,
        document: String,
        field: String,
        payload: Option<Vec<u8>>,
    }
    
    #[async_std::main]
    async fn main() -> anyhow::Result<()> {
    	let db_create = "db0".as_bytes();
    	let mut packet = vec![0x02];
    	packet.extend_from_slice(&db_create);
    
        let mut buffer = [0; BUFFER_CAPACITY];
        let mut container_buffer: Vec<u8> = Vec::new();
        let mut bytes_read: usize;
        let mut current_buffer_size = 0_usize;
        
        let mut stream = TcpStream::connect("127.0.0.1:4343").await?;
        stream.write(&packet).await?;
    
        loop {
            bytes_read = stream.read(&mut buffer).await?;
            
    
            // Add the new buffer length to the current buffer size
            current_buffer_size += buffer[..bytes_read].len();
    
            // Check if the current stream is less than the buffer capacity, if so all data has been received
            if  buffer[..bytes_read].len() < BUFFER_CAPACITY {
                // Ensure that the data is appended before being deserialized by bincode
                container_buffer.append(&mut buffer[..bytes_read].to_owned());
    			dbg!(&container_buffer);
    
    			dbg!(bincode::deserialize::<DbOps>(&container_buffer).unwrap());
    		
    			break;
                
            }
            // Append data to buffer
            container_buffer.append(&mut buffer[..bytes_read].to_owned());        
        }
    
        Ok(())
    }
    

数据库支持当前支持的查询方法

  1. 仓库查询

    • turingdb_helpers::RepoQuery::create() 在当前目录中创建一个新的仓库
    • turingdb_helpers::RepoQuery::drop() 删除当前目录中的仓库
  2. 数据库查询

    • DbQuery::create() 在存储库中创建一个新的数据库

      use turingdb_helpers::DatabaseQuery;
      
      let mut foo = DatabaseQuery::new().await;
      foo
        .db("db_name").await
        .create().await;
      
    • DbQuery::drop() 在存储库中删除一个数据库

      use turingdb_helpers::DatabaseQuery;
      
      let mut foo = DatabaseQuery::new().await;
      foo
      	.db("db_name").await
      	.drop().await;
      
    • DbQuery::list() 列出存储库中的所有数据库

      use turingdb_helpers::DatabaseQuery;
      
      let mut foo = Database::new().await;
      foo.drop().await;
      
  3. 文档查询

    • DocumentQuery::create() 在数据库中创建一个文档

      use turingdb_helpers::DocumentQuery;
      
      let mut foo = DocumentQuery::new().await;
      foo
      	.db("db_name").await
      	.document("document_name").await
      	.create().await;
      
    • DocumentQuery::drop() 在数据库中删除一个文档

      use turingdb_helpers::DocumentQuery;
      
      let mut foo = DocumentQuery::new().await;
      foo
      	.db("db_name").await
      	.document("document_name").await
      	.drop().await;
      
    • DocumentQuery::list() 列出数据库中的所有文档

      use turingdb_helpers::DocumentQuery;
      
      let mut foo = DocumentQuery::new().await;
      foo
      	.db("db_name").await
      	.list().await;
      
  4. 字段查询

    • Field::set() 基于键在文档中创建一个字段

      use turingdb_helpers::FieldQuery;
      
      let mut foo = FieldQuery::new().await;
      let data = "my_data_converted_into_bytes".as_bytes();
      foo
        .db("db_name").await
        .document("document_name").await
        .field("field_name").await
        .payload(data).await
        .set().await
      
    • Field::get() 基于键获取文档中的字段

      use turingdb_helpers::FieldQuery;
      
      let mut foo = FieldQuery::new().await;
      foo
        .db("db_name").await
        .document("document_name").await
        .field("field_name").await
        .get().await
      
    • Field::modify() 基于键更新文档中的字段

      use turingdb_helpers::FieldQuery;
      
      let mut foo = FieldQuery::new().await;
      let data = "my_new_data_converted_into_bytes".as_bytes();
      foo
        .db("db_name").await
        .document("document_name").await
        .field("field_name").await
        .payload(data).await
        .modify().await
      
    • Field::remove() 基于键从文档中删除一个字段

      use turingdb_helpers::FieldQuery;
      
      let mut foo = FieldQuery::new().await;
      foo
        .db("db_name").await
        .document("document_name").await
        .field("field_name").await
        .remove().await
      
    • Field::list() 获取所有字段的键

      use turingdb_helpers::FieldQuery;
      
      let mut foo = FieldQuery::new().await;
      foo
        .db("db_name").await
        .document("document_name").await
        .list().await
      

警告

一个文档不能持有超过 16MiB 的数据,如果超过此阈值,则会从 custom_codes 包的 DbOps::EncounteredErrors([TuringDB::<GLOBAL>::(ERROR)-BUFFER_CAPACITY_EXCEEDED_16MB])

贡献

我们在做出贡献时遵循 Rust 行为准则

许可

对本项目的所有代码贡献都必须使用 Apache 许可证

致谢

本项目使用的所有库都受其自身许可的约束

依赖

~7MB
~116K SLoC