A simple Rust library for working with Google Bigtable Data API V2 .
This library might be production ready. Any contribution or help is highly appreciated.
I had the idea to build a client like this and got some input from others see here and porting code from here (thanks to @mvines).
Code for read_rows parsing logic is tested by porting Google's Java client tests code with json test cases as raw input.
Current idea is to make this library very light weighted, and you assemble requests based on Google Bigtable V2 protobuf schema and send the requests via tonic gRPC over HTTP/2. So the user have the flexibility of creating any type of Bigtable request and use this client to talk to Bigtable service.
Compiled Bigtable API proto as Rust code is also included in the repo here so users don't need to compile from proto again.
The returned row values from Bigtable is parsed by this library.
Supported interfaces towards Bigtable:
For other gRPC APIs/methods, one should be able to use the gRCP client directly and assemble the request you need to interact with Bigtable service via building the Protobuf messages (already complied as rs files and included here).
gcp_auth is used, which supports:
- Application Default Credentials
- Connection authenticated via Google service account key
json
file (by settingGOOGLE_APPLICATION_CREDENTIALS=path/to/key.json
environment parameter) - Default service account by retrieving a token from the gcloud metadata server
You can use the library as follows:
[dependencies]
bigtable_rs = "0.2.6"
tokio = { version = "1.0", features = ["rt-multi-thread"] }
env_logger = "0.9.1"
Documentation is on crate.io. See examples folders for more examples. The following example showing how to do a key range scan
use bigtable_rs::bigtable;
use bigtable_rs::google::bigtable::v2::row_filter::{Chain, Filter};
use bigtable_rs::google::bigtable::v2::row_range::{EndKey, StartKey};
use bigtable_rs::google::bigtable::v2::{ReadRowsRequest, RowFilter, RowRange, RowSet};
use env_logger;
use std::error::Error;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
env_logger::init();
let project_id = "project-id";
let instance_name = "instance-1";
let table_name = "table-1";
let channel_size = 4;
let timeout = Duration::from_secs(10);
let key_start: String = "key1".to_owned();
let key_end: String = "key4".to_owned();
// make a bigtable client
let connection = bigtable::BigTableConnection::new(
project_id,
instance_name,
true,
channel_size,
Some(timeout),
)
.await?;
let mut bigtable = connection.client();
// prepare a ReadRowsRequest
let request = ReadRowsRequest {
table_name: bigtable.get_full_table_name(table_name),
rows_limit: 10,
rows: Some(RowSet {
row_keys: vec![], // use this field to put keys for reading specific rows
row_ranges: vec![RowRange {
start_key: Some(StartKey::StartKeyClosed(key_start.into_bytes())),
end_key: Some(EndKey::EndKeyOpen(key_end.into_bytes())),
}],
}),
filter: Some(RowFilter {
filter: Some(Filter::Chain(Chain {
filters: vec![
RowFilter {
filter: Some(Filter::FamilyNameRegexFilter("cf1".to_owned())),
},
RowFilter {
filter: Some(Filter::ColumnQualifierRegexFilter("c1".as_bytes().to_vec())),
},
RowFilter {
filter: Some(Filter::CellsPerColumnLimitFilter(2)),
},
],
})),
}),
..ReadRowsRequest::default()
};
// calling bigtable API to get results
let response = bigtable.read_rows(request).await?;
// simply print results for example usage
response.into_iter().for_each(|(key, data)| {
println!("------------\n{}", String::from_utf8(key.clone()).unwrap());
data.into_iter().for_each(|row_cell| {
println!(
" [{}:{}] \"{}\" @ {}",
row_cell.family_name,
String::from_utf8(row_cell.qualifier).unwrap(),
String::from_utf8(row_cell.value).unwrap(),
row_cell.timestamp_micros
)
})
});
Ok(())
}
To start develop or test the example code above, install cbt tool if you haven't, then start a test Bigtable instance locally and insert some test data like this:
# at one terminal, start a bigtable insatnce locally
. start_bigtable_local.sh
# at another terminal, load some data into it
. start_load_table_local.sh
Then run an example with this command:
BIGTABLE_EMULATOR_HOST=localhost:8086 RUST_LOG=bigtable_rs=trace cargo run --bin simple_read
If you see error related to google authentication or gcp project not found,
then remember to set environment parameter BIGTABLE_EMULATOR_HOST=localhost:8086
so to let the example's client connect onto the local emulator.
To run it against real Bigtable instance:
GOOGLE_APPLICATION_CREDENTIALS=<path_to_key>/service_account_key.json cargo run --bin simple_read
Or if you want to use your gcloud auth login
auth then simply run the client without any special env settings:
cargo run --bin simple_read
See examples
folders for more examples.
Clone this repo, then checkout the submodules if necesary
cd googleapis
git submodule init
git submodule update
Then checkout bigtable_rs/src/build.rs
to update Google protos
Running tests:
cargo test -- --nocapture
rustup component add llvm-tools-preview
cargo install grcov
mkdir -p target/coverage/html
CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' cargo test
grcov . --binary-path ./target/debug/deps/ -s . -t html --branch --ignore-not-existing --ignore '../*' --ignore "/*" --ignore "bigtable_rs/src/google/*" --keep-only "bigtable_rs/src/*" -o target/coverage/html