-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix/batch length #824
Fix/batch length #824
Changes from 1 commit
4c013e8
772c46f
efb96fc
ec5cf68
a23e6eb
b35346b
6ecaa03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,7 @@ criterion = "0.4" # Note: v0.5 needs at least rust 1.70.0 | |
tracing-subscriber = { version = "0.3.14", features = ["env-filter"] } | ||
assert_matches = "1.5.0" | ||
rand_chacha = "0.3.1" | ||
bcs = "0.1.5" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's not add new dependencies when it isn't necessary. let mut key = vec![0];
serialize_into(&mut key, &(i as usize)).unwrap(); Can be written as: let mut key = vec![0];
key.extend(i.to_be_bytes().as_slice());
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thought so too, was trying to fully replicate the issue. Fixed now |
||
|
||
[[bench]] | ||
name = "benchmark" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
use bcs::serialize_into; | ||
use scylla_cql::errors::{BadQuery, QueryError}; | ||
|
||
use crate::batch::BatchType; | ||
use crate::query::Query; | ||
use crate::{ | ||
batch::Batch, | ||
prepared_statement::PreparedStatement, | ||
test_utils::{create_new_session_builder, unique_keyspace_name}, | ||
IntoTypedRows, QueryResult, Session, | ||
}; | ||
|
||
#[tokio::test] | ||
async fn test_large_batch_statements() { | ||
let mut session = create_new_session_builder().build().await.unwrap(); | ||
let ks = unique_keyspace_name(); | ||
session = create_test_session(session, &ks).await; | ||
|
||
let max_number_of_queries = u16::MAX as usize; | ||
write_batch(&session, max_number_of_queries).await; | ||
|
||
let key_prefix = vec![0]; | ||
let keys = find_keys_by_prefix(&session, key_prefix.clone()).await; | ||
assert_eq!(keys.len(), max_number_of_queries); | ||
|
||
let too_many_queries = u16::MAX as usize + 1; | ||
|
||
let err = write_batch(&session, too_many_queries).await; | ||
|
||
assert!(err.is_err()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make sure that the error is actually There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, knew there was a way to do this without having to implement |
||
} | ||
|
||
async fn create_test_session(session: Session, ks: &String) -> Session { | ||
session | ||
.query( | ||
format!("CREATE KEYSPACE IF NOT EXISTS {} WITH REPLICATION = {{ 'class' : 'SimpleStrategy', 'replication_factor' : 1 }}",ks), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please change |
||
&[], | ||
) | ||
.await.unwrap(); | ||
session | ||
.query("DROP TABLE IF EXISTS kv.pairs;", &[]) | ||
.await | ||
.unwrap(); | ||
session | ||
.query( | ||
"CREATE TABLE IF NOT EXISTS kv.pairs (dummy int, k blob, v blob, primary key (dummy, k))", | ||
&[], | ||
) | ||
.await.unwrap(); | ||
session | ||
} | ||
|
||
async fn write_batch(session: &Session, n: usize) -> Result<QueryResult, QueryError> { | ||
let mut batch_query = Batch::new(BatchType::Logged); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An |
||
let mut batch_values = Vec::new(); | ||
for i in 0..n { | ||
let mut key = vec![0]; | ||
serialize_into(&mut key, &(i as usize)).unwrap(); | ||
let value = key.clone(); | ||
let query = "INSERT INTO kv.pairs (dummy, k, v) VALUES (0, ?, ?)"; | ||
let values = vec![key, value]; | ||
batch_values.push(values); | ||
let query = Query::new(query); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about using prepared statements instead? Prepare the statement once before creating the batch and then use it in |
||
batch_query.append_statement(query); | ||
} | ||
session.batch(&batch_query, batch_values).await | ||
} | ||
|
||
async fn find_keys_by_prefix(session: &Session, key_prefix: Vec<u8>) -> Vec<Vec<u8>> { | ||
let len = key_prefix.len(); | ||
let rows = match get_upper_bound_option(&key_prefix) { | ||
None => { | ||
let values = (key_prefix,); | ||
let query = "SELECT k FROM kv.pairs WHERE dummy = 0 AND k >= ? ALLOW FILTERING"; | ||
session.query(query, values).await.unwrap() | ||
} | ||
Some(upper_bound) => { | ||
let values = (key_prefix, upper_bound); | ||
let query = | ||
"SELECT k FROM kv.pairs WHERE dummy = 0 AND k >= ? AND k < ? ALLOW FILTERING"; | ||
session.query(query, values).await.unwrap() | ||
} | ||
}; | ||
let mut keys = Vec::new(); | ||
if let Some(rows) = rows.rows { | ||
for row in rows.into_typed::<(Vec<u8>,)>() { | ||
let key = row.unwrap(); | ||
let short_key = key.0[len..].to_vec(); | ||
keys.push(short_key); | ||
} | ||
} | ||
keys | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TBH I don't really follow the logic of key prefixes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. modified the tests to be simpler, but still show the intent of batch queries |
||
fn get_upper_bound_option(key_prefix: &[u8]) -> Option<Vec<u8>> { | ||
let len = key_prefix.len(); | ||
for i in (0..len).rev() { | ||
let val = key_prefix[i]; | ||
if val < u8::MAX { | ||
let mut upper_bound = key_prefix[0..i + 1].to_vec(); | ||
upper_bound[i] += 1; | ||
return Some(upper_bound); | ||
} | ||
} | ||
None | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The maximum value of
u16
is 65,535 - one less than 65,536.https://doc.rust-lang.org/std/primitive.u16.html#associatedconstant.MAX
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd also be nice to display the number of queries that the user has passed. This can be done by adding
(usize)
to the enum variant and displaying it with{0}
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice Catch. Fixed