-
Notifications
You must be signed in to change notification settings - Fork 11
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
cargo: update rust driver's version to 0.13.1 #138
Conversation
@Lorak-mmk @wprzytula Any ideas why the unit tests using scylla-proxy fail? In both tests, |
My idea why this happens is: if you choose a specific commit for scylla-proxy, then |
The culprit is this: scylladb/scylla-rust-driver#770. |
OK, a solution is to alter the proxy rules in the test code not to drop the control connection, but instead return a DB error on attempt to fetch metadata. This way the driver does not suffer from lack of connections in the pool. Just change this function in a following way: fn generic_drop_queries_rules() -> impl IntoIterator<Item = RequestRule> {
[RequestRule(
Condition::RequestOpcode(RequestOpcode::Query),
// We won't respond to any queries (including metadata fetch),
// but the driver will manage to continue with dummy metadata.
// RequestReaction::drop_connection(), <--- this is removed
RequestReaction::forge().server_error(), // <---- this is added instead
)]
} |
scylla-rust-wrapper/src/value.rs
Outdated
CassCqlValue::Tuple(t) => { | ||
// We allow serializing tuples that have less fields | ||
// than the database tuple, but not the other way around. |
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.
Why so? Source? cpp-driver or Rust driver?
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.
This is a logic from rust-driver. I'll check how cpp-driver behaves in this case.
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.
equals
implementation for Tuples in cpp-driver:
virtual bool equals(const DataType::ConstPtr& data_type) const {
assert(value_type() == CASS_VALUE_TYPE_TUPLE);
if (value_type() != data_type->value_type()) {
return false;
}
const ConstPtr& tuple_type(data_type);
// Only compare sub-types if both have sub-types
if (!types_.empty() && !tuple_type->types_.empty()) {
if (types_.size() != tuple_type->types_.size()) {
return false;
}
for (size_t i = 0; i < types_.size(); ++i) {
if (!types_[i]->equals(tuple_type->types_[i])) {
return false;
}
}
}
return true;
}
So we should not allow serializing tuples that have less fields than the DB tuple. However, notice that this check is performed during cass_statement_bind_tuple*
. It is something that Karol mentioned in other comment. There are no checks during serialization itself.
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.
As a side note: equals
implementation for UDTs is a bit more flexible in cpp-driver:
virtual bool equals(const DataType::ConstPtr& data_type) const {
assert(value_type() == CASS_VALUE_TYPE_UDT);
if (data_type->value_type() != CASS_VALUE_TYPE_UDT) {
return false;
}
const UserType::ConstPtr& user_type(data_type);
if (!equals_both_not_empty(keyspace_, user_type->keyspace_)) {
return false;
}
if (!equals_both_not_empty(type_name_, user_type->type_name_)) {
return false;
}
// UDT's can be considered equal as long as the mutual first fields shared
// between them are equal. UDT's are append only as far as fields go, so a
// newer 'version' of the UDT data type after a schema change event should be
// treated as equivalent in this scenario, by simply looking at the first N
// mutual fields they should share.
size_t min_fields_size = std::min(fields_.size(), user_type->fields_.size());
for (size_t i = 0; i < min_fields_size; ++i) {
if (fields_[i].name != user_type->fields_[i].name ||
!fields_[i].type->equals(user_type->fields_[i].type)) {
return false;
}
}
return true;
}
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.
Regarding the tuples: as we discussed yesterday @muzarski types and sizes are only checked for typed tuple (cass_tuple_new_from_data_type
), not for untyped tuple (cass_tuple_new
)
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.
Please make sure that semantics of tuples and UDTs match those in cpp-driver
One integration test failed:
Isn't it weird that we get a server error that never occured before, after bumping the driver's version? |
The issue can be reproduced in rust driver: #[tokio::test]
async fn test_counter_batch() {
setup_tracing();
let session = Arc::new(create_new_session_builder().build().await.unwrap());
let ks = unique_keyspace_name();
session.query(format!("CREATE KEYSPACE IF NOT EXISTS {} WITH REPLICATION = {{'class' : 'NetworkTopologyStrategy', 'replication_factor' : 1}}", ks), &[]).await.unwrap();
session
.query(
format!(
"CREATE TABLE IF NOT EXISTS {}.t_batch (key int PRIMARY KEY, value counter)",
ks
),
&[],
)
.await
.unwrap();
let q = format!("UPDATE {}.t_batch SET value = value + ? WHERE key = ?", ks);
let mut my_batch = Batch::new(BatchType::Counter);
assert_eq!(BatchType::Counter, my_batch.get_type());
my_batch.append_statement(&q[..]);
my_batch.append_statement(&q[..]);
my_batch.append_statement(&q[..]);
session
.batch(
&my_batch,
((Counter(1), 2), (Counter(1), 2), (Counter(1), 2)),
)
.await
.unwrap();
} The error:
This seems like a rust-driver issue, since you can clearly see that I've set the cc: @Lorak-mmk @wprzytula |
Please open an issue in Rust driver repo. Also, specify what version of the driver behaves correctly and what version misbehaves. If you feel like, perform |
@wprzytula I opened a PR in rust-driver that will fix the failing test: scylladb/scylla-rust-driver#1038. I think that we should filter out the failing test for now, and include it again when new release of rust-driver with a fix is out (unless we can wait for new release if it happens anytime soon, but I don't think so). |
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.
There is a is_compatible_type function in binding module. Is it really necessary, when we already do a type checking in our SerializeCql implementation? Can this be removed?
Rust Driver's type checking happens when we serialize the values, which in cpp-rust-driver happens during a call to e.g. cass_session_execute
.
is_compatible_type
is called in binding functions like cass_statement_bind_*
.
We have to either implement it at some point, or wait for Rust Driver to introduce BoundStatement and use it in cpp-rust-driver.
For some reason, I could not add a driver's dependency with a standard version = "0.13" notation. I had to use a VCS path to a specific commit. The reason is that, otherwise, rust compiler would complain about scylla-rust-wrapper and scylla-proxy using different versions of DbError enum - even though, I changed the version of scylla-proxy, and it points to the commit of 0.13 release (scylladb/scylla-rust-driver@e68adf5).
Can you use a tag when specifying dependency, instead of commit hash? Main disadvantage of specifying commit hash is that it's not obvious which version it follows, but tag would solve it.
7bd9775
to
ae38fe8
Compare
v2: addressed review comments |
v2.1: bumped rust driver's version to 0.13.1 |
Co-authored-by: Karol Baryła <[email protected]>
scylla-rust-wrapper/src/value.rs
Outdated
|
||
fn mk_typck_err<T>( | ||
got: &ColumnType, | ||
kind: impl Into<BuiltinTypeCheckErrorKind>, | ||
) -> SerializationError { | ||
mk_typck_err_named(std::any::type_name::<T>(), got, kind) | ||
} | ||
|
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.
Please add a TODO (or even better: issue here and in rust driver) to export relevant functions from scylla-cql so there is not need for coppy-paste here.
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.
I suggest exporting such internal utility functions shared between Rust driver and cpp-rust-driver using #[doc(hidden)]
attribute, as this gives us freedom to modify this as non-public API.
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.
Or we could add a feature cpp-rust-wrapper
and only export if it is enabled.
scylla-rust-wrapper/src/value.rs
Outdated
CassCqlValue::Tuple(t) => { | ||
// We allow serializing tuples that have less fields | ||
// than the database tuple, but not the other way around. |
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.
Please make sure that semantics of tuples and UDTs match those in cpp-driver
Proxy would drop connection during metadata fetch which causes some tests to fail.
v3: as discussed with @Lorak-mmk offline, we decided to follow the same approach as cpp-driver - we don't do any typechecks during serialization. The type checks are supposed to take place during binding (e.g. binding value to tuple or statement). This approach is better, since we can separate typecheck and serialization logic - this is really handful for untyped tuples and collections (cpp-driver allows users to define such objects). In this PR, we only introduce a naive serialization logic (custom It's worth noting that we do not lose anything, since type checks were not performed by previous version of rust driver anyway. |
Opened an issue on what should be implemented in follow-up PR with typechecks: #142. |
Fix: #126
This PR updates the rust driver's version to 0.13.1
API breaking changes
First commit fixes some minor issues caused by API breaking changes in rust driver.
Serialization
Following commits focus on serialization. This version of rust driver already uses a new serialization framework which validates the types. In result, some integration tests are failing, since cpp-driver uses a bit different rust-to-CQL type mapping. A simple example is a
i64
value which can be mapped to 4 CQL types:bigint/counter/time/timestamp
.In this PR we address and fix this issue. We introduce a
CassCqlValue
enum which is a narrower version of rust driver'sCqlValue
with a customSerializeValue
(still calledSerializeCql
in 0.13) implementation. The serialization DOES NOT contain any typechecks. The typechecks will be introduced in a follow-up PR. We want to follow the same approach as cpp-driver, and do the typechecks during bindings (i.e. binding value to collection, tuple, UDT or statement).Pre-review checklist
[ ] I have enabled appropriate tests in.github/workflows/build.yml
ingtest_filter
.[ ] I have enabled appropriate tests in.github/workflows/cassandra.yml
ingtest_filter
.