fluss/lib.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Apache Fluss (Incubating) Official Rust Client
19//!
20//! Official Rust client library for [Apache Fluss (Incubating)](https://fluss.apache.org/).
21//! It supports **primary key (KV) tables** (upsert + lookup) and **log tables** (append + scan).
22//!
23//! # Examples
24//!
25//! ## Primary key table and log table
26//!
27//! Connect to a cluster, create a KV table (upsert and lookup), then a log table (append and scan):
28//!
29//! ```rust,no_run
30//! use fluss::client::EARLIEST_OFFSET;
31//! use fluss::client::FlussConnection;
32//! use fluss::config::Config;
33//! use fluss::error::Result;
34//! use fluss::metadata::{DataTypes, Schema, TableDescriptor, TablePath};
35//! use fluss::row::{GenericRow, InternalRow};
36//! use std::time::Duration;
37//!
38//! #[tokio::main]
39//! async fn main() -> Result<()> {
40//! let mut config = Config::default();
41//! config.bootstrap_servers = "127.0.0.1:9123".to_string();
42//! let connection = FlussConnection::new(config).await?;
43//! let admin = connection.get_admin()?;
44//!
45//! // ---- Primary key (KV) table: upsert and lookup ----
46//! let kv_path = TablePath::new("fluss", "users");
47//! let mut kv_schema = Schema::builder()
48//! .column("id", DataTypes::int())
49//! .column("name", DataTypes::string())
50//! .column("age", DataTypes::bigint())
51//! .primary_key(vec!["id"]);
52//! let kv_descriptor = TableDescriptor::builder()
53//! .schema(kv_schema.build()?)
54//! .build()?;
55//! admin.create_table(&kv_path, &kv_descriptor, false).await?;
56//!
57//! let kv_table = connection.get_table(&kv_path).await?;
58//! let upsert_writer = kv_table.new_upsert()?.create_writer()?;
59//! let mut row = GenericRow::new(3);
60//! row.set_field(0, 1i32);
61//! row.set_field(1, "Alice");
62//! row.set_field(2, 30i64);
63//! upsert_writer.upsert(&row)?;
64//! upsert_writer.flush().await?;
65//!
66//! let mut lookuper = kv_table.new_lookup()?.create_lookuper()?;
67//! let mut key = GenericRow::new(1);
68//! key.set_field(0, 1i32);
69//! let result = lookuper.lookup(&key).await?;
70//! if let Some(r) = result.get_single_row()? {
71//! println!("KV lookup: id={}, name={}, age={}",
72//! r.get_int(0)?, r.get_string(1)?, r.get_long(2)?);
73//! }
74//!
75//! // ---- Log table: append and scan ----
76//! let log_path = TablePath::new("fluss", "events");
77//! let mut log_schema_builder = Schema::builder()
78//! .column("ts", DataTypes::bigint())
79//! .column("message", DataTypes::string());
80//! let log_descriptor = TableDescriptor::builder()
81//! .schema(log_schema_builder.build()?)
82//! .build()?;
83//! admin.create_table(&log_path, &log_descriptor, false).await?;
84//!
85//! let log_table = connection.get_table(&log_path).await?;
86//! let append_writer = log_table.new_append()?.create_writer()?;
87//! let mut event = GenericRow::new(2);
88//! event.set_field(0, 1700000000i64);
89//! event.set_field(1, "hello");
90//! append_writer.append(&event)?;
91//! append_writer.flush().await?;
92//!
93//! let scanner = log_table.new_scan().create_log_scanner()?;
94//! scanner.subscribe(0, EARLIEST_OFFSET).await?;
95//! let scan_records = scanner.poll(Duration::from_secs(1)).await?;
96//! for record in scan_records {
97//! let r = record.row();
98//! println!("Log scan: ts={}, message={}", r.get_long(0)?, r.get_string(1)?);
99//! }
100//!
101//! Ok(())
102//! }
103//! ```
104//!
105//! # Performance
106//!
107//! For production deployments on Linux, we recommend using
108//! [jemalloc](https://crates.io/crates/tikv-jemallocator) as the global allocator.
109//! The default glibc allocator (ptmalloc2) can cause RSS bloat and fragmentation under
110//! sustained write loads due to repeated same-size alloc/free cycles in Arrow batch building.
111//! jemalloc's thread-local size-class bins handle this pattern efficiently.
112//!
113//! ```toml
114//! [target.'cfg(not(target_env = "msvc"))'.dependencies]
115//! tikv-jemallocator = "0.6"
116//! ```
117//!
118//! ```rust,ignore
119//! #[cfg(not(target_env = "msvc"))]
120//! #[global_allocator]
121//! static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
122//! ```
123
124pub mod client;
125pub mod metadata;
126pub mod record;
127pub mod row;
128pub mod rpc;
129
130mod cluster;
131pub use cluster::{ServerNode, ServerType};
132
133pub mod config;
134pub mod error;
135
136mod bucketing;
137mod compression;
138pub mod io;
139mod util;
140
141#[cfg(test)]
142mod test_utils;
143
144pub type TableId = i64;
145pub type PartitionId = i64;
146pub type BucketId = i32;
147
148pub mod proto {
149 include!(concat!(env!("OUT_DIR"), "/proto.rs"));
150}