From d68233f1c7a54094b114f8add6393b6c0c4da5da Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Fri, 25 Sep 2015 11:22:41 -0700 Subject: [PATCH 01/13] Fixed build for Xcode 6/7 --- CMakeLists.txt | 19 +++---------------- packaging/homebrew/cassandra-cpp-driver.rb | 10 +++++----- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da5dd1daa..b41dded72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -442,22 +442,9 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Clang/Intel specific compiler options # I disabled long-long warning because boost generates about 50 such warnings - set(WARNING_COMPILER_FLAGS "-Wall -pedantic -Wextra -Wno-long-long -Wno-unused-parameter -Wno-variadic-macros -Wno-zero-length-array") - - # Detect if this is Apple's clang - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -v ERROR_VARIABLE CASS_CLANG_VERSION_INFO) - if (CASS_CLANG_VERSION_INFO MATCHES "^Apple LLVM") - set(CASS_IS_APPLE_CLANG 1) - else() - set(CASS_IS_APPLE_CLANG 0) - endif() - - if(NOT CASS_IS_APPLE_CLANG AND - (${CMAKE_CXX_COMPILER_VERSION} VERSION_EQUAL "3.6" OR - ${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER "3.6") - ) - set(WARNING_COMPILER_FLAGS "${WARNING_COMPILER_FLAGS} -Wno-unused-local-typedef ") - endif() + set(WARNING_COMPILER_FLAGS "-Wall -pedantic -Wextra -Wno-long-long -Wno-unused-parameter") + set(WARNING_COMPILER_FLAGS "${WARNING_COMPILER_FLAGS} -Wno-variadic-macros -Wno-zero-length-array") + set(WARNING_COMPILER_FLAGS "${WARNING_COMPILER_FLAGS} -Wno-unused-local-typedef -Wno-unknown-warning-option") # OpenSSL is deprecated on later versions of Mac OS X. The long-term solution # is to provide a CommonCryto implementation. diff --git a/packaging/homebrew/cassandra-cpp-driver.rb b/packaging/homebrew/cassandra-cpp-driver.rb index af12bfa7e..dd6d9ecae 100644 --- a/packaging/homebrew/cassandra-cpp-driver.rb +++ b/packaging/homebrew/cassandra-cpp-driver.rb @@ -2,18 +2,18 @@ class CassandraCppDriver < Formula homepage "http://datastax.github.io/cpp-driver/" - url "https://github.com/datastax/cpp-driver/archive/2.0.1.tar.gz" - sha1 "67a5b4e52ec421407c34ba7df109faeeaf4ef6dd" - version "2.0.1" + url "https://github.com/datastax/cpp-driver/archive/2.2.0-beta1.tar.gz" + sha1 "6159f1a5e31a044fb70567f849286572afa57174" + version "2.2.0-beta1" - head "git://github.com:datastax/cpp-driver.git", :branch => "2.0" + head "git://github.com:datastax/cpp-driver.git", :branch => "master" depends_on "cmake" => :build depends_on "libuv" def install mkdir 'build' do - system "cmake", "-DCMAKE_BUILD_TYPE=RELEASE", "-DCASS_BUILD_STATIC=ON", "-DCMAKE_INSTALL_PREFIX:PATH=#{prefix}", ".." + system "cmake", "-DCMAKE_BUILD_TYPE=RELEASE", "-DCASS_BUILD_STATIC=ON", "-DCMAKE_INSTALL_PREFIX:PATH=#{prefix}", "-DCMAKE_INSTALL_LIBDIR=#{lib}", ".." system "make", "install" end end From 8ab05f1ab24ec333aab74023d9284c6df2f5671d Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Tue, 6 Oct 2015 16:10:27 -0700 Subject: [PATCH 02/13] Schema metadata clean up before refactor --- include/cassandra.h | 4 +- src/cluster_metadata.cpp | 65 ---------------- src/cluster_metadata.hpp | 68 ----------------- src/control_connection.cpp | 36 ++++----- src/external_types.hpp | 2 +- src/future.cpp | 6 +- src/replication_strategy.cpp | 1 + src/replication_strategy.hpp | 4 +- src/request_handler.hpp | 6 +- src/result_metadata.hpp | 4 +- src/schema_metadata.cpp | 142 +++++++++++++++++++++-------------- src/schema_metadata.hpp | 119 ++++++++++++++++++++++------- src/session.cpp | 14 ++-- src/session.hpp | 9 +-- src/testing.cpp | 4 +- src/token_map.hpp | 1 - 16 files changed, 220 insertions(+), 265 deletions(-) delete mode 100644 src/cluster_metadata.cpp delete mode 100644 src/cluster_metadata.hpp diff --git a/include/cassandra.h b/include/cassandra.h index 3504e4be3..61faa2159 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -1502,7 +1502,7 @@ cass_session_execute_batch(CassSession* session, * @see cass_schema_free() */ CASS_EXPORT const CassSchema* -cass_session_get_schema(CassSession* session); +cass_session_get_schema(const CassSession* session); /** * Gets a copy of this session's performance/diagnostic metrics. @@ -1515,7 +1515,7 @@ cass_session_get_schema(CassSession* session); * @see cass_schema_free() */ CASS_EXPORT void -cass_session_get_metrics(CassSession* session, +cass_session_get_metrics(const CassSession* session, CassMetrics* output); /*********************************************************************************** diff --git a/src/cluster_metadata.cpp b/src/cluster_metadata.cpp deleted file mode 100644 index 89c2fdbb7..000000000 --- a/src/cluster_metadata.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright (c) 2014-2015 DataStax - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include "cluster_metadata.hpp" - -namespace cass { - -ClusterMetadata::ClusterMetadata() { - uv_mutex_init(&schema_mutex_); -} - -ClusterMetadata::~ClusterMetadata() { - uv_mutex_destroy(&schema_mutex_); -} - -void ClusterMetadata::clear() { - schema_.clear(); - token_map_.clear(); -} - -void ClusterMetadata::update_keyspaces(ResultResponse* result) { - Schema::KeyspacePointerMap keyspaces; - { - ScopedMutex l(&schema_mutex_); - keyspaces = schema_.update_keyspaces(result); - } - for (Schema::KeyspacePointerMap::const_iterator i = keyspaces.begin(); i != keyspaces.end(); ++i) { - token_map_.update_keyspace(i->first, *i->second); - } -} - -void ClusterMetadata::update_tables(ResultResponse* table_result, ResultResponse* col_result) { - ScopedMutex l(&schema_mutex_); - schema_.update_tables(table_result, col_result); -} - -void ClusterMetadata::update_usertypes(ResultResponse* usertypes_result) { - ScopedMutex l(&schema_mutex_); - schema_.update_usertypes(usertypes_result); -} - -void ClusterMetadata::drop_keyspace(const std::string& keyspace_name) { - schema_.drop_keyspace(keyspace_name); - token_map_.drop_keyspace(keyspace_name); -} - -Schema* ClusterMetadata::copy_schema() const { - ScopedMutex l(&schema_mutex_); - return new Schema(schema_); -} - -} // namespace cass diff --git a/src/cluster_metadata.hpp b/src/cluster_metadata.hpp deleted file mode 100644 index ebb100948..000000000 --- a/src/cluster_metadata.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright (c) 2014-2015 DataStax - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef __CASS_CLUSTER_METADATA_HPP_INCLUDED__ -#define __CASS_CLUSTER_METADATA_HPP_INCLUDED__ - -#include "token_map.hpp" -#include "schema_metadata.hpp" - -namespace cass { - -class ClusterMetadata { -public: - ClusterMetadata(); - ~ClusterMetadata(); - - void clear(); - void update_keyspaces(ResultResponse* result); - void update_tables(ResultResponse* table_result, ResultResponse* col_result); - void update_usertypes(ResultResponse* usertypes_result); - void set_partitioner(const std::string& partitioner_class) { token_map_.set_partitioner(partitioner_class); } - void update_host(SharedRefPtr& host, const TokenStringList& tokens) { token_map_.update_host(host, tokens); } - void build() { token_map_.build(); } - void drop_keyspace(const std::string& keyspace_name); - void drop_table(const std::string& keyspace_name, const std::string& table_name) { - schema_.drop_table(keyspace_name, table_name); - } - void drop_type(const std::string& keyspace_name, const std::string& type_name) { - schema_.drop_type(keyspace_name, type_name); - } - void remove_host(SharedRefPtr& host) { token_map_.remove_host(host); } - - const Schema& schema() const { return schema_; } - Schema* copy_schema() const;// synchronized copy for API - - SharedRefPtr get_user_type(const std::string& keyspace, - const std::string& type_name) const { - return schema_.get_user_type(keyspace, type_name); - } - - void set_protocol_version(int version) { schema_.set_protocol_version(version); } - - const TokenMap& token_map() const { return token_map_; } - -private: - Schema schema_; - TokenMap token_map_; - - // Used to synch schema updates and copies - mutable uv_mutex_t schema_mutex_; -}; - -} // namespace cass - -#endif diff --git a/src/control_connection.cpp b/src/control_connection.cpp index ca4cd114b..31a9af9fd 100644 --- a/src/control_connection.cpp +++ b/src/control_connection.cpp @@ -188,7 +188,7 @@ void ControlConnection::on_ready(Connection* connection) { connection->address().to_string().c_str()); // A protocol version is need to encode/decode maps properly - session_->cluster_meta().set_protocol_version(protocol_version_); + session_->metadata().set_protocol_version(protocol_version_); // The control connection has to refresh meta when there's a reconnect because // events could have been missed while not connected. @@ -255,7 +255,7 @@ void ControlConnection::on_event(EventResponse* response) { SharedRefPtr host = session_->get_host(response->affected_node()); if (host) { session_->on_remove(host); - session_->cluster_meta().remove_host(host); + session_->metadata().remove_host(host); } else { LOG_DEBUG("Tried to remove host %s that doesn't exist", address_str.c_str()); } @@ -269,7 +269,7 @@ void ControlConnection::on_event(EventResponse* response) { refresh_node_info(host, false, true); } else { LOG_DEBUG("Move event for host %s that doesn't exist", address_str.c_str()); - session_->cluster_meta().remove_host(host); + session_->metadata().remove_host(host); } break; } @@ -318,14 +318,14 @@ void ControlConnection::on_event(EventResponse* response) { case EventResponse::DROPPED: switch (response->schema_change_target()) { case EventResponse::KEYSPACE: - session_->cluster_meta().drop_keyspace(response->keyspace().to_string()); + session_->metadata().drop_keyspace(response->keyspace().to_string()); break; case EventResponse::TABLE: - session_->cluster_meta().drop_table(response->keyspace().to_string(), + session_->metadata().drop_table(response->keyspace().to_string(), response->target().to_string()); break; case EventResponse::TYPE: - session_->cluster_meta().drop_type(response->keyspace().to_string(), + session_->metadata().drop_type(response->keyspace().to_string(), response->target().to_string()); break; } @@ -368,7 +368,7 @@ void ControlConnection::on_query_meta_all(ControlConnection* control_connection, Session* session = control_connection->session_; - session->cluster_meta().clear(); + session->metadata().clear(); bool is_initial_connection = (control_connection->state_ == CONTROL_STATE_NEW); @@ -436,13 +436,13 @@ void ControlConnection::on_query_meta_all(ControlConnection* control_connection, session->purge_hosts(is_initial_connection); if (session->config().use_schema()) { - session->cluster_meta().update_keyspaces(static_cast(responses[2].get())); - session->cluster_meta().update_tables(static_cast(responses[3].get()), - static_cast(responses[4].get())); + session->metadata().update_keyspaces(static_cast(responses[2].get())); + session->metadata().update_tables(static_cast(responses[3].get()), + static_cast(responses[4].get())); if (control_connection->protocol_version_ >= 3) { - session->cluster_meta().update_usertypes(static_cast(responses[5].get())); + session->metadata().update_types(static_cast(responses[5].get())); } - session->cluster_meta().build(); + session->metadata().build(); } if (is_initial_connection) { @@ -597,7 +597,7 @@ void ControlConnection::update_node_info(SharedRefPtr host, const Row* row if (query_tokens_) { std::string partitioner; if (row->get_string_by_name("partitioner", &partitioner)) { - session_->cluster_meta().set_partitioner(partitioner); + session_->metadata().set_partitioner(partitioner); } v = row->get_by_name("tokens"); if (v != NULL) { @@ -607,7 +607,7 @@ void ControlConnection::update_node_info(SharedRefPtr host, const Row* row tokens.push_back(i.value()->to_string_ref()); } if (!tokens.empty()) { - session_->cluster_meta().update_host(host, tokens); + session_->metadata().update_host(host, tokens); } } } @@ -637,7 +637,7 @@ void ControlConnection::on_refresh_keyspace(ControlConnection* control_connectio keyspace_name.c_str()); return; } - control_connection->session_->cluster_meta().update_keyspaces(result); + control_connection->session_->metadata().update_keyspaces(result); } void ControlConnection::refresh_table(const StringRef& keyspace_name, @@ -671,8 +671,8 @@ void ControlConnection::on_refresh_table(ControlConnection* control_connection, } Session* session = control_connection->session_; - session->cluster_meta().update_tables(column_family_result, - static_cast(responses[1].get())); + session->metadata().update_tables(static_cast(responses[0].get()), + static_cast(responses[1].get())); } @@ -702,7 +702,7 @@ void ControlConnection::on_refresh_type(ControlConnection* control_connection, keyspace_and_type_names.first.c_str()); return; } - control_connection->session_->cluster_meta().update_usertypes(result); + control_connection->session_->metadata().update_types(result); } bool ControlConnection::handle_query_invalid_response(Response* response) { diff --git a/src/external_types.hpp b/src/external_types.hpp index 9803a4d2c..013066678 100644 --- a/src/external_types.hpp +++ b/src/external_types.hpp @@ -71,7 +71,7 @@ EXTERNAL_TYPE(cass::Iterator, CassIterator); EXTERNAL_TYPE(cass::Row, CassRow); EXTERNAL_TYPE(cass::Value, CassValue); EXTERNAL_TYPE(cass::SslContext, CassSsl); -EXTERNAL_TYPE(cass::Schema, CassSchema); +EXTERNAL_TYPE(cass::Metadata::Snapshot, CassSchema); EXTERNAL_TYPE(cass::SchemaMetadata, CassSchemaMeta); EXTERNAL_TYPE(cass::SchemaMetadataField, CassSchemaMetaField); EXTERNAL_TYPE(cass::UuidGen, CassUuidGen); diff --git a/src/future.cpp b/src/future.cpp index 1abb7010e..b6ff6cbcb 100644 --- a/src/future.cpp +++ b/src/future.cpp @@ -81,9 +81,9 @@ const CassPrepared* cass_future_get_prepared(CassFuture* future) { cass::SharedRefPtr result(response_future->response()); if (result && result->kind() == CASS_RESULT_KIND_PREPARED) { std::vector key_aliases; - response_future->schema.get_table_key_columns(result->keyspace().to_string(), - result->table().to_string(), - &key_aliases); + response_future->snapshot->get_table_key_columns(result->keyspace().to_string(), + result->table().to_string(), + &key_aliases); cass::Prepared* prepared = new cass::Prepared(result, response_future->statement, key_aliases); prepared->inc_ref(); diff --git a/src/replication_strategy.cpp b/src/replication_strategy.cpp index d23b35077..9ece344fa 100644 --- a/src/replication_strategy.cpp +++ b/src/replication_strategy.cpp @@ -18,6 +18,7 @@ #include "logger.hpp" #include "map_iterator.hpp" +#include "schema_metadata.hpp" #include "token_map.hpp" #include "utils.hpp" diff --git a/src/replication_strategy.hpp b/src/replication_strategy.hpp index 9ef9041ce..9790da3b5 100644 --- a/src/replication_strategy.hpp +++ b/src/replication_strategy.hpp @@ -20,12 +20,14 @@ #include "buffer.hpp" #include "host.hpp" #include "ref_counted.hpp" -#include "schema_metadata.hpp" #include namespace cass { +class KeyspaceMetadata; +class SchemaMetadataField; + typedef std::vector Token; typedef std::map > TokenHostMap; typedef std::map TokenReplicaMap; diff --git a/src/request_handler.hpp b/src/request_handler.hpp index 9bd0c0fa2..33aea975c 100644 --- a/src/request_handler.hpp +++ b/src/request_handler.hpp @@ -41,9 +41,9 @@ class Timer; class ResponseFuture : public Future { public: - ResponseFuture(const Schema& schema) + ResponseFuture(const Metadata& metadata) : Future(CASS_FUTURE_TYPE_RESPONSE) - , schema(schema) { } + , snapshot(metadata.snapshot()) { } void set_response(Address address, const SharedRefPtr& response) { ScopedMutex lock(&mutex_); @@ -79,7 +79,7 @@ class ResponseFuture : public Future { } std::string statement; - Schema schema; + ScopedPtr snapshot; private: Address address_; diff --git a/src/result_metadata.hpp b/src/result_metadata.hpp index 5b7786093..c24b4e94e 100644 --- a/src/result_metadata.hpp +++ b/src/result_metadata.hpp @@ -14,8 +14,8 @@ limitations under the License. */ -#ifndef __CASS_METADATA_HPP_INCLUDED__ -#define __CASS_METADATA_HPP_INCLUDED__ +#ifndef __CASS_RESULT_METADATA_HPP_INCLUDED__ +#define __CASS_RESULT_METADATA_HPP_INCLUDED__ #include "cassandra.h" #include "data_type.hpp" diff --git a/src/schema_metadata.cpp b/src/schema_metadata.cpp index 5d1eb877c..b67139c86 100644 --- a/src/schema_metadata.cpp +++ b/src/schema_metadata.cpp @@ -25,6 +25,7 @@ #include "result_iterator.hpp" #include "row.hpp" #include "row_iterator.hpp" +#include "scoped_lock.hpp" #include "value.hpp" #include "third_party/rapidjson/rapidjson/document.h" @@ -45,7 +46,7 @@ const CassSchemaMeta* cass_schema_get_keyspace(const CassSchema* schema, const CassSchemaMeta* cass_schema_get_keyspace_n(const CassSchema* schema, const char* keyspace, size_t keyspace_length) { - return CassSchemaMeta::to(schema->get(std::string(keyspace, keyspace_length))); + return CassSchemaMeta::to(schema->get_keyspace(std::string(keyspace, keyspace_length))); } CassSchemaMetaType cass_schema_meta_type(const CassSchemaMeta* meta) { @@ -68,7 +69,7 @@ const CassDataType* cass_schema_get_udt_n(const CassSchema* schema, std::string keyspace_id(keyspace, keyspace_length); std::string type_name_id(type_name, type_name_length); cass::SharedRefPtr user_type - = schema->get_user_type(cass::to_cql_id(keyspace_id), + = schema->get_type(cass::to_cql_id(keyspace_id), cass::to_cql_id(type_name_id)); return CassDataType::to(user_type.get()); } @@ -141,6 +142,9 @@ const CassSchemaMetaField* cass_iterator_get_schema_meta_field(CassIterator* ite namespace cass { +template +const T& as_const(const T& x) { return x; } + template const T* find_by_name(const std::map& map, const std::string& name) { typename std::map::const_iterator it = map.find(name); @@ -148,27 +152,29 @@ const T* find_by_name(const std::map& map, const std::string& na return &it->second; } -const SchemaMetadata* Schema::get(const std::string& name) const { - return find_by_name(*keyspaces_, name); +const SchemaMetadata* Metadata::Snapshot::get_keyspace(const std::string& name) const { + KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(name); + if (i == keyspaces_->end()) return NULL; + return i->second.get(); } -SharedRefPtr Schema::get_user_type(const std::string& keyspace, - const std::string& type_name) const +SharedRefPtr Metadata::Snapshot::get_type(const std::string& keyspace_name, + const std::string& type_name) const { - KeyspaceUserTypeMap::const_iterator i = user_types_->find(keyspace); - if (i == user_types_->end()) { - return SharedRefPtr(); - } - - UserTypeMap::const_iterator j = i->second.find(type_name); - if (j == i->second.end()) { - return SharedRefPtr(); - } + KeyspaceMetadata::Map::const_iterator i = as_const(keyspaces_)->find(keyspace_name); + if (i == as_const(keyspaces_)->end()) { + return SharedRefPtr(); + } + return i->second->get_type(type_name); +} - return j->second; +Metadata::Snapshot* Metadata::snapshot() const { + ScopedMutex l(&mutex_); + return new Snapshot(snapshot_); } -Schema::KeyspacePointerMap Schema::update_keyspaces(ResultResponse* result) { +void Metadata::update_keyspaces(ResultResponse* result) { + ScopedMutex l(&mutex_); KeyspacePointerMap updates; SharedRefPtr buffer = result->buffer(); @@ -184,22 +190,26 @@ Schema::KeyspacePointerMap Schema::update_keyspaces(ResultResponse* result) { continue; } - KeyspaceMetadata* ks_meta = get_or_create(keyspace_name); - ks_meta->update(protocol_version_, buffer, row); - updates.insert(std::make_pair(keyspace_name, ks_meta)); + KeyspaceMetadata::Ptr keyspace = snapshot_.get_or_create_keyspace(keyspace_name); + keyspace->update(protocol_version_, buffer, row); + updates.insert(std::make_pair(keyspace_name, keyspace)); + } + + for (KeyspacePointerMap::const_iterator i = updates.begin(); i != updates.end(); ++i) { + token_map_.update_keyspace(i->first, *i->second); } - return updates; } -void Schema::update_tables(ResultResponse* table_result, ResultResponse* col_result) { - SharedRefPtr buffer = table_result->buffer(); +void Metadata::update_tables(ResultResponse* tables_result, ResultResponse* columns_result) { + ScopedMutex l(&mutex_); + SharedRefPtr buffer = tables_result->buffer(); - table_result->decode_first_row(); - ResultIterator rows(table_result); + tables_result->decode_first_row(); + ResultIterator rows(tables_result); std::string keyspace_name; std::string columnfamily_name; - KeyspaceMetadata* keyspace_metadata = NULL; + KeyspaceMetadata::Ptr keyspace; while (rows.next()) { std::string temp_keyspace_name; @@ -213,18 +223,19 @@ void Schema::update_tables(ResultResponse* table_result, ResultResponse* col_res if (keyspace_name != temp_keyspace_name) { keyspace_name = temp_keyspace_name; - keyspace_metadata = get_or_create(keyspace_name); + keyspace = snapshot_.get_or_create_keyspace(keyspace_name); } - keyspace_metadata->get_or_create(columnfamily_name)->update(protocol_version_, buffer, row); + keyspace->get_or_create_table(columnfamily_name)->update(protocol_version_, buffer, row); } - update_columns(col_result); -} -void Schema::update_usertypes(ResultResponse* usertypes_result) { + update_columns(columns_result); +} - usertypes_result->decode_first_row(); - ResultIterator rows(usertypes_result); +void Metadata::update_types(ResultResponse* result) { + ScopedMutex l(&mutex_); + result->decode_first_row(); + ResultIterator rows(result); while (rows.next()) { std::string keyspace_name; @@ -286,12 +297,14 @@ void Schema::update_usertypes(ResultResponse* usertypes_result) { fields.push_back(UserType::Field(field_name, data_type)); } - (*user_types_)[keyspace_name][type_name] - = SharedRefPtr(new UserType(keyspace_name, type_name, fields)); + snapshot_.get_or_create_keyspace(keyspace_name)->add_type( + SharedRefPtr(new UserType(keyspace_name, type_name, fields))); } } -void Schema::update_columns(ResultResponse* result) { +void Metadata::update_columns(ResultResponse* result) { + // DO NOT LOCK: This is private and called from update_tables(). + SharedRefPtr buffer = result->buffer(); result->decode_first_row(); @@ -300,7 +313,7 @@ void Schema::update_columns(ResultResponse* result) { std::string keyspace_name; std::string columnfamily_name; std::string column_name; - TableMetadata* table_metadata = NULL; + TableMetadata* table = NULL; std::set cleared_tables; while (rows.next()) { std::string temp_keyspace_name; @@ -318,35 +331,34 @@ void Schema::update_columns(ResultResponse* result) { columnfamily_name != temp_columnfamily_name) { keyspace_name = temp_keyspace_name; columnfamily_name = temp_columnfamily_name; - table_metadata = get_or_create(keyspace_name)->get_or_create(columnfamily_name); - std::pair::iterator, bool> pos_success = cleared_tables.insert(table_metadata); - if (pos_success.second) { - table_metadata->clear_columns(); + table = snapshot_.get_or_create_keyspace(keyspace_name)->get_or_create_table(columnfamily_name); + if (cleared_tables.insert(table).second) { + table->clear_columns(); } } - table_metadata->get_or_create(column_name)->update(protocol_version_, buffer, row); + table->get_or_create(column_name)->update(protocol_version_, buffer, row); } } -void Schema::drop_keyspace(const std::string& keyspace_name) { - keyspaces_->erase(keyspace_name); +void Metadata::drop_keyspace(const std::string& keyspace_name) { + snapshot_.keyspaces_->erase(keyspace_name); } -void Schema::drop_table(const std::string& keyspace_name, const std::string& table_name) { - KeyspaceMetadata::Map::iterator it = keyspaces_->find(keyspace_name); - if (it == keyspaces_->end()) return; - it->second.drop_table(table_name); +void Metadata::drop_table(const std::string& keyspace_name, const std::string& table_name) { + KeyspaceMetadata::Map::iterator it = snapshot_.keyspaces_->find(keyspace_name); + if (it == snapshot_.keyspaces_->end()) return; + it->second->drop_table(table_name); } -void Schema::drop_type(const std::string& keyspace_name, const std::string& type_name) { - KeyspaceUserTypeMap::iterator it = user_types_->find(keyspace_name); - if (it == user_types_->end()) return; - it->second.erase(type_name); +void Metadata::drop_type(const std::string& keyspace_name, const std::string& type_name) { + KeyspaceMetadata::Map::iterator it = snapshot_.keyspaces_->find(keyspace_name); + if (it == snapshot_.keyspaces_->end()) return; + it->second->drop_type(type_name); } -void Schema::clear() { - keyspaces_->clear(); +void Metadata::clear() { + snapshot_.keyspaces_->clear(); } const SchemaMetadataField* SchemaMetadata::get_field(const std::string& name) const { @@ -469,6 +481,12 @@ const SchemaMetadata* KeyspaceMetadata::get_entry(const std::string& name) const return find_by_name(tables_, name); } +SharedRefPtr KeyspaceMetadata::get_type(const std::string& type_name) const { + UserTypeMap::const_iterator i = types_.find(type_name); + if (i == types_.end()) return SharedRefPtr(); + return i->second; +} + void KeyspaceMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { add_field(buffer, row, "keyspace_name"); add_field(buffer, row, "durable_writes"); @@ -476,10 +494,18 @@ void KeyspaceMetadata::update(int version, const SharedRefPtr& buffer add_json_map_field(version, row, "strategy_options"); } +void KeyspaceMetadata::add_type(const SharedRefPtr& user_type) { + types_[user_type->type_name()] = user_type; +} + void KeyspaceMetadata::drop_table(const std::string& table_name) { tables_.erase(table_name); } +void KeyspaceMetadata::drop_type(const std::string& type_name) { + types_.erase(type_name); +} + const SchemaMetadata* TableMetadata::get_entry(const std::string& name) const { return find_by_name(columns_, name); } @@ -556,10 +582,10 @@ void ColumnMetadata::update(int version, const SharedRefPtr& buffer, add_field(buffer, row, "index_type"); } -void Schema::get_table_key_columns(const std::string& ks_name, - const std::string& table_name, - std::vector* output) const { - const SchemaMetadata* ks_meta = get(ks_name); +void Metadata::Snapshot::get_table_key_columns(const std::string& ks_name, + const std::string& table_name, + std::vector* output) const { + const SchemaMetadata* ks_meta = get_keyspace(ks_name); if (ks_meta != NULL) { const SchemaMetadata* table_meta = static_cast(ks_meta)->get_entry(table_name); if (table_meta != NULL) { diff --git a/src/schema_metadata.hpp b/src/schema_metadata.hpp index d8bb4f576..21c6f9647 100644 --- a/src/schema_metadata.hpp +++ b/src/schema_metadata.hpp @@ -19,8 +19,10 @@ #include "copy_on_write_ptr.hpp" #include "iterator.hpp" +#include "ref_counted.hpp" #include "scoped_lock.hpp" #include "scoped_ptr.hpp" +#include "token_map.hpp" #include "type_parser.hpp" #include @@ -191,10 +193,13 @@ class TableMetadata : public SchemaMetadata { ColumnMetadata::Map columns_; }; -class KeyspaceMetadata : public SchemaMetadata { +class KeyspaceMetadata : public SchemaMetadata, public RefCounted { public: - typedef std::map Map; + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef CopyOnWritePtr MapPtr; typedef SchemaMetadataIteratorImpl TableIterator; + typedef std::map > UserTypeMap; KeyspaceMetadata() : SchemaMetadata(CASS_SCHEMA_META_TYPE_KEYSPACE) {} @@ -202,59 +207,117 @@ class KeyspaceMetadata : public SchemaMetadata { virtual const SchemaMetadata* get_entry(const std::string& name) const; virtual Iterator* iterator() const { return new TableIterator(tables_); } - TableMetadata* get_or_create(const std::string& name) { return &tables_[name]; } + TableMetadata* get_or_create_table(const std::string& name) { return &tables_[name]; } + + SharedRefPtr get_type(const std::string& type_name) const; + void update(int version, const SharedRefPtr& buffer, const Row* row); + void add_type(const SharedRefPtr& user_type); + void drop_table(const std::string& table_name); + void drop_type(const std::string& type_name); std::string strategy_class() const { return get_string_field("strategy_class"); } const SchemaMetadataField* strategy_options() const { return get_field("strategy_options"); } private: TableMetadata::Map tables_; + UserTypeMap types_; }; -class Schema { +class Metadata { public: - typedef SchemaMetadataIteratorImpl KeyspaceIterator; - typedef std::map KeyspacePointerMap; - typedef std::map > UserTypeMap; - typedef std::map KeyspaceUserTypeMap; + class KeyspaceIterator : public SchemaMetadataIterator { + public: + typedef typename SchemaMapIteratorImpl::Map Map; + + KeyspaceIterator(const Map& map) + : impl_(map) {} + + virtual bool next() { return impl_.next(); } + virtual const SchemaMetadata* meta() const { return impl_.item()->get(); } + + private: + SchemaMapIteratorImpl impl_; + }; + typedef std::map KeyspacePointerMap; + + class Snapshot { + public: + Snapshot() + : keyspaces_(new KeyspaceMetadata::Map()) { } + + const SchemaMetadata* get_keyspace(const std::string& name) const; + + SharedRefPtr get_type(const std::string& keyspace_name, + const std::string& type_name) const; + + Iterator* iterator() const { return new KeyspaceIterator(*keyspaces_); } + + void get_table_key_columns(const std::string& ks_name, + const std::string& cf_name, + std::vector* output) const; + + private: + // We don't want external snapshots to be modified + friend class Metadata; - Schema() - : keyspaces_(new KeyspaceMetadata::Map) - , user_types_(new KeyspaceUserTypeMap) - , protocol_version_(0) {} + const KeyspaceMetadata::Ptr& get_or_create_keyspace(const std::string& keyspace_name) { + KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); + if (i == keyspaces_->end()) { + i = keyspaces_->insert(std::make_pair(keyspace_name, + KeyspaceMetadata::Ptr(new KeyspaceMetadata()))).first; + } + return i->second; + } + + + private: + KeyspaceMetadata::MapPtr keyspaces_; + }; + + + Metadata() + : protocol_version_(0) { + uv_mutex_init(&mutex_); + } + + ~Metadata() { + uv_mutex_destroy(&mutex_); + } + + Snapshot* snapshot() const; void set_protocol_version(int version) { protocol_version_ = version; } - const SchemaMetadata* get(const std::string& name) const; - Iterator* iterator() const { return new KeyspaceIterator(*keyspaces_); } + void update_keyspaces(ResultResponse* result); + void update_tables(ResultResponse* tables_result, ResultResponse* columns_result); + void update_types(ResultResponse* result); - SharedRefPtr get_user_type(const std::string& keyspace, - const std::string& type_name) const; - - KeyspaceMetadata* get_or_create(const std::string& name) { return &(*keyspaces_)[name]; } - KeyspacePointerMap update_keyspaces(ResultResponse* result); - void update_tables(ResultResponse* table_result, ResultResponse* col_result); - void update_usertypes(ResultResponse* usertypes_result); void drop_keyspace(const std::string& keyspace_name); void drop_table(const std::string& keyspace_name, const std::string& table_name); void drop_type(const std::string& keyspace_name, const std::string& type_name); + void clear(); - void get_table_key_columns(const std::string& ks_name, - const std::string& cf_name, - std::vector* output) const; + + void set_partitioner(const std::string& partitioner_class) { token_map_.set_partitioner(partitioner_class); } + void update_host(SharedRefPtr& host, const TokenStringList& tokens) { token_map_.update_host(host, tokens); } + void build() { token_map_.build(); } + void remove_host(SharedRefPtr& host) { token_map_.remove_host(host); } + + const TokenMap& token_map() const { return token_map_; } private: void update_columns(ResultResponse* result); private: - // Really coarse grain copy-on-write. This could be made - // more fine grain, but it might not be worth the work. - CopyOnWritePtr keyspaces_; - CopyOnWritePtr user_types_; + // This lock prevents partial snapshots when updating metadata + mutable uv_mutex_t mutex_; + + Snapshot snapshot_; + TokenMap token_map_; // Only used internally on a single thread, there's // no need for copy-on-write. diff --git a/src/session.cpp b/src/session.cpp index 33ef5c1db..a372217d4 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -92,11 +92,11 @@ CassFuture* cass_session_execute_batch(CassSession* session, const CassBatch* ba return CassFuture::to(session->execute(batch->from())); } -const CassSchema* cass_session_get_schema(CassSession* session) { - return CassSchema::to(session->copy_schema()); +const CassSchema* cass_session_get_schema(const CassSession* session) { + return CassSchema::to(session->metadata().snapshot()); } -void cass_session_get_metrics(CassSession* session, +void cass_session_get_metrics(const CassSession* session, CassMetrics* metrics) { const cass::Metrics* internal_metrics = session->metrics(); @@ -163,7 +163,7 @@ void Session::clear(const Config& config) { } io_workers_.clear(); request_queue_.reset(); - cluster_meta_.clear(); + metadata_.clear(); control_connection_.clear(); current_host_mark_ = true; pending_resolve_count_ = 0; @@ -510,7 +510,7 @@ Future* Session::prepare(const char* statement, size_t length) { PrepareRequest* prepare = new PrepareRequest(); prepare->set_query(statement, length); - ResponseFuture* future = new ResponseFuture(cluster_meta_.schema()); + ResponseFuture* future = new ResponseFuture(metadata_); future->inc_ref(); // External reference future->statement.assign(statement, length); @@ -585,7 +585,7 @@ void Session::on_down(SharedRefPtr host) { } Future* Session::execute(const RoutableRequest* request) { - ResponseFuture* future = new ResponseFuture(cluster_meta_.schema()); + ResponseFuture* future = new ResponseFuture(metadata_); future->inc_ref(); // External reference RetryPolicy* retry_policy @@ -665,7 +665,7 @@ QueryPlan* Session::new_query_plan(const Request* request, Request::EncodingCach connected_keyspace = io_workers_[0]->keyspace(); } return load_balancing_policy_->new_query_plan(connected_keyspace, request, - cluster_meta_.token_map(), cache); + metadata_.token_map(), cache); } } // namespace cass diff --git a/src/session.hpp b/src/session.hpp index 2af82c7f6..6c67f08e0 100644 --- a/src/session.hpp +++ b/src/session.hpp @@ -17,7 +17,6 @@ #ifndef __CASS_SESSION_HPP_INCLUDED__ #define __CASS_SESSION_HPP_INCLUDED__ -#include "cluster_metadata.hpp" #include "config.hpp" #include "control_connection.hpp" #include "event_thread.hpp" @@ -100,7 +99,7 @@ class Session : public EventThread { Future* prepare(const char* statement, size_t length); Future* execute(const RoutableRequest* statement); - const Schema* copy_schema() const { return cluster_meta_.copy_schema(); } + const Metadata& metadata() const { return metadata_; } int protocol_version() const { return control_connection_.protocol_version(); @@ -144,9 +143,7 @@ class Session : public EventThread { SharedRefPtr add_host(const Address& address); void purge_hosts(bool is_initial_connection); - ClusterMetadata& cluster_meta() { - return cluster_meta_; - } + Metadata& metadata() { return metadata_; } void on_control_connection_ready(); void on_control_connection_error(CassError code, const std::string& message); @@ -173,7 +170,7 @@ class Session : public EventThread { IOWorkerVec io_workers_; ScopedPtr > > request_queue_; - ClusterMetadata cluster_meta_; + Metadata metadata_; ControlConnection control_connection_; bool current_host_mark_; int pending_resolve_count_; diff --git a/src/testing.cpp b/src/testing.cpp index 84a4602fb..cabf7e1d0 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -65,7 +65,7 @@ CassSchemaMeta* get_schema_meta_from_keyspace(const CassSchema* schema, const st CassSchemaMeta* foundSchemaMeta = NULL; if (schema) { - foundSchemaMeta = reinterpret_cast(const_cast(schema->from()->get(keyspace))); + foundSchemaMeta = reinterpret_cast(const_cast(schema->from()->get_keyspace(keyspace))); } return foundSchemaMeta; @@ -74,7 +74,7 @@ CassSchemaMeta* get_schema_meta_from_keyspace(const CassSchema* schema, const st std::vector get_user_data_type_field_names(const CassSchema* schema, const std::string& keyspace, const std::string& udt_name) { std::vector udt_field_names; if (schema) { - SharedRefPtr udt = schema->from()->get_user_type(keyspace, udt_name); + SharedRefPtr udt = schema->from()->get_type(keyspace, udt_name); if (udt) { for (cass::UserType::FieldVec::const_iterator it = udt->fields().begin(); it != udt->fields().end(); ++it) { udt_field_names.push_back((*it).name); diff --git a/src/token_map.hpp b/src/token_map.hpp index f6cf59465..f0feec285 100644 --- a/src/token_map.hpp +++ b/src/token_map.hpp @@ -22,7 +22,6 @@ #include "host.hpp" #include "replication_strategy.hpp" #include "scoped_ptr.hpp" -#include "schema_metadata.hpp" #include "string_ref.hpp" #include From 0957ad9eb766d748e40ee9d50ea65c4cd1aa914f Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Tue, 6 Oct 2015 16:19:09 -0700 Subject: [PATCH 03/13] Rename "schema_metadata.hpp/cpp" to "metadata.hpp/cpp" --- src/control_connection.cpp | 2 +- src/external_types.hpp | 2 +- src/{schema_metadata.cpp => metadata.cpp} | 2 +- src/{schema_metadata.hpp => metadata.hpp} | 0 src/replication_strategy.cpp | 2 +- src/request_handler.hpp | 2 +- src/session.hpp | 2 +- src/testing.cpp | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename src/{schema_metadata.cpp => metadata.cpp} (99%) rename src/{schema_metadata.hpp => metadata.hpp} (100%) diff --git a/src/control_connection.cpp b/src/control_connection.cpp index 31a9af9fd..0258316fe 100644 --- a/src/control_connection.cpp +++ b/src/control_connection.cpp @@ -21,11 +21,11 @@ #include "event_response.hpp" #include "load_balancing.hpp" #include "logger.hpp" +#include "metadata.hpp" #include "query_request.hpp" #include "result_iterator.hpp" #include "error_response.hpp" #include "result_response.hpp" -#include "schema_metadata.hpp" #include "session.hpp" #include "timer.hpp" diff --git a/src/external_types.hpp b/src/external_types.hpp index 013066678..76c695676 100644 --- a/src/external_types.hpp +++ b/src/external_types.hpp @@ -25,12 +25,12 @@ #include "error_response.hpp" #include "future.hpp" #include "iterator.hpp" +#include "metadata.hpp" #include "prepared.hpp" #include "result_response.hpp" #include "request.hpp" #include "retry_policy.hpp" #include "row.hpp" -#include "schema_metadata.hpp" #include "session.hpp" #include "ssl.hpp" #include "statement.hpp" diff --git a/src/schema_metadata.cpp b/src/metadata.cpp similarity index 99% rename from src/schema_metadata.cpp rename to src/metadata.cpp index b67139c86..f6a348849 100644 --- a/src/schema_metadata.cpp +++ b/src/metadata.cpp @@ -14,7 +14,7 @@ limitations under the License. */ -#include "schema_metadata.hpp" +#include "metadata.hpp" #include "buffer.hpp" #include "collection_iterator.hpp" diff --git a/src/schema_metadata.hpp b/src/metadata.hpp similarity index 100% rename from src/schema_metadata.hpp rename to src/metadata.hpp diff --git a/src/replication_strategy.cpp b/src/replication_strategy.cpp index 9ece344fa..31a5e00e2 100644 --- a/src/replication_strategy.cpp +++ b/src/replication_strategy.cpp @@ -18,7 +18,7 @@ #include "logger.hpp" #include "map_iterator.hpp" -#include "schema_metadata.hpp" +#include "metadata.hpp" #include "token_map.hpp" #include "utils.hpp" diff --git a/src/request_handler.hpp b/src/request_handler.hpp index 33aea975c..57e168855 100644 --- a/src/request_handler.hpp +++ b/src/request_handler.hpp @@ -23,10 +23,10 @@ #include "handler.hpp" #include "host.hpp" #include "load_balancing.hpp" +#include "metadata.hpp" #include "request.hpp" #include "response.hpp" #include "retry_policy.hpp" -#include "schema_metadata.hpp" #include "scoped_ptr.hpp" #include diff --git a/src/session.hpp b/src/session.hpp index 6c67f08e0..296d384f9 100644 --- a/src/session.hpp +++ b/src/session.hpp @@ -24,11 +24,11 @@ #include "host.hpp" #include "io_worker.hpp" #include "load_balancing.hpp" +#include "metadata.hpp" #include "metrics.hpp" #include "mpmc_queue.hpp" #include "ref_counted.hpp" #include "row.hpp" -#include "schema_metadata.hpp" #include "scoped_lock.hpp" #include "scoped_ptr.hpp" diff --git a/src/testing.cpp b/src/testing.cpp index cabf7e1d0..f7e951b03 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -19,9 +19,9 @@ #include "address.hpp" #include "get_time.hpp" #include "logger.hpp" +#include "metadata.hpp" #include "murmur3.hpp" #include "result_response.hpp" -#include "schema_metadata.hpp" #include "external_types.hpp" namespace cass { From 8ea423eaa7e8a2bb9a9441979875bfd621f1e656 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Tue, 6 Oct 2015 16:31:35 -0700 Subject: [PATCH 04/13] Schema metadata API refactor --- examples/schema_meta/schema_meta.c | 117 +-- examples/udt/udt.c | 14 +- include/cassandra.h | 634 +++++++++---- src/control_connection.cpp | 17 +- src/control_connection.hpp | 2 +- src/external_types.hpp | 8 +- src/future.cpp | 6 +- src/metadata.cpp | 883 ++++++++++++------ src/metadata.hpp | 358 ++++--- src/replication_strategy.cpp | 8 +- src/replication_strategy.hpp | 10 +- src/request_handler.hpp | 4 +- src/session.cpp | 4 +- src/testing.cpp | 16 +- src/testing.hpp | 4 +- src/value.cpp | 15 + src/value.hpp | 3 + .../src/test_schema_metadata.cpp | 148 +-- test/integration_tests/src/test_udts.cpp | 19 +- test/integration_tests/src/test_utils.hpp | 8 +- test/unit_tests/src/test_copy_on_write.cpp | 55 ++ 21 files changed, 1595 insertions(+), 738 deletions(-) diff --git a/examples/schema_meta/schema_meta.c b/examples/schema_meta/schema_meta.c index 7d7ac83d2..806a87a25 100644 --- a/examples/schema_meta/schema_meta.c +++ b/examples/schema_meta/schema_meta.c @@ -28,29 +28,30 @@ #include #include -void print_schema_meta(const CassSchemaMeta* meta, int indent); +void print_keyspace_meta(const CassKeyspaceMeta* meta, int indent); +void print_table_meta(const CassTableMeta* meta, int indent); void print_keyspace(CassSession* session, const char* keyspace) { - const CassSchema* schema = cass_session_get_schema(session); - const CassSchemaMeta* keyspace_meta = cass_schema_get_keyspace(schema, keyspace); + const CassSchemaMeta* schema_meta = cass_session_get_schema_meta(session); + const CassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta, keyspace); if (keyspace_meta != NULL) { - print_schema_meta(keyspace_meta, 0); + print_keyspace_meta(keyspace_meta, 0); } else { fprintf(stderr, "Unable to find \"%s\" keyspace in the schema metadata\n", keyspace); } - cass_schema_free(schema); + cass_schema_meta_free(schema_meta); } void print_table(CassSession* session, const char* keyspace, const char* table) { - const CassSchema* schema = cass_session_get_schema(session); - const CassSchemaMeta* keyspace_meta = cass_schema_get_keyspace(schema, keyspace); + const CassSchemaMeta* schema_meta = cass_session_get_schema_meta(session); + const CassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta, keyspace); if (keyspace_meta != NULL) { - const CassSchemaMeta* table_meta = cass_schema_meta_get_entry(keyspace_meta, table); + const CassTableMeta* table_meta = cass_keyspace_meta_table_by_name(keyspace_meta, table); if (table_meta != NULL) { - print_schema_meta(table_meta, 0); + print_table_meta(table_meta, 0); } else { fprintf(stderr, "Unable to find \"%s\" table in the schema metadata\n", table); } @@ -58,7 +59,7 @@ void print_table(CassSession* session, const char* keyspace, const char* table) fprintf(stderr, "Unable to find \"%s\" keyspace in the schema metadata\n", keyspace); } - cass_schema_free(schema); + cass_schema_meta_free(schema_meta); } void print_error(CassFuture* future) { @@ -129,9 +130,9 @@ int main() { void print_schema_value(const CassValue* value); void print_schema_list(const CassValue* value); void print_schema_map(const CassValue* value); -void print_schema_meta_field(const CassSchemaMetaField* field, int indent); -void print_schema_meta_fields(const CassSchemaMeta* meta, int indent); -void print_schema_meta_entries(const CassSchemaMeta* meta, int indent); +void print_meta_field(const CassMetaField* field, int indent); +void print_meta_fields(CassIterator* iterator, int indent); +void print_column_meta(const CassColumnMeta* meta, int indent); void print_indent(int indent) { int i; @@ -227,13 +228,13 @@ void print_schema_map(const CassValue* value) { cass_iterator_free(iterator); } -void print_schema_meta_field(const CassSchemaMetaField* field, int indent) { +void print_meta_field(const CassMetaField* field, int indent) { const char* name; size_t name_length; const CassValue* value; - cass_schema_meta_field_name(field, &name, &name_length); - value = cass_schema_meta_field_value(field); + cass_meta_field_name(field, &name, &name_length); + value = cass_meta_field_value(field); print_indent(indent); printf("%.*s: ", (int)name_length, name); @@ -241,55 +242,63 @@ void print_schema_meta_field(const CassSchemaMetaField* field, int indent) { printf("\n"); } -void print_schema_meta_fields(const CassSchemaMeta* meta, int indent) { - CassIterator* fields = cass_iterator_fields_from_schema_meta(meta); - - while (cass_iterator_next(fields)) { - print_schema_meta_field(cass_iterator_get_schema_meta_field(fields), indent); +void print_meta_fields(CassIterator* iterator, int indent) { + while (cass_iterator_next(iterator)) { + print_meta_field(cass_iterator_get_meta_field(iterator), indent); } - cass_iterator_free(fields); + cass_iterator_free(iterator); } -void print_schema_meta_entries(const CassSchemaMeta* meta, int indent) { - CassIterator* entries = cass_iterator_from_schema_meta(meta); +void print_keyspace_meta(const CassKeyspaceMeta* meta, int indent) { + const char* name; + size_t name_length; + CassIterator* iterator; + + print_indent(indent); + cass_keyspace_meta_name(meta, &name, &name_length); + printf("Keyspace \"%.*s\":\n", (int)name_length, name); + + print_meta_fields(cass_iterator_fields_from_keyspace_meta(meta), indent + 1); + printf("\n"); - while (cass_iterator_next(entries)) { - print_schema_meta(cass_iterator_get_schema_meta(entries), indent); + iterator = cass_iterator_tables_from_keyspace_meta(meta); + while (cass_iterator_next(iterator)) { + print_table_meta(cass_iterator_get_table_meta(iterator), indent + 1); } - cass_iterator_free(entries); + printf("\n"); + + cass_iterator_free(iterator); } -void print_schema_meta(const CassSchemaMeta* meta, int indent) { - const CassSchemaMetaField* field = NULL; +void print_table_meta(const CassTableMeta* meta, int indent) { const char* name; size_t name_length; - print_indent(indent); + CassIterator* iterator; - switch (cass_schema_meta_type(meta)) { - case CASS_SCHEMA_META_TYPE_KEYSPACE: - field = cass_schema_meta_get_field(meta, "keyspace_name"); - cass_value_get_string(cass_schema_meta_field_value(field), &name, &name_length); - printf("Keyspace \"%.*s\":\n", (int)name_length, name); - print_schema_meta_fields(meta, indent + 1); - printf("\n"); - print_schema_meta_entries(meta, indent + 1); - break; + print_indent(indent); + cass_table_meta_name(meta, &name, &name_length); + printf("Table \"%.*s\":\n", (int)name_length, name); - case CASS_SCHEMA_META_TYPE_TABLE: - field = cass_schema_meta_get_field(meta, "columnfamily_name"); - cass_value_get_string(cass_schema_meta_field_value(field), &name, &name_length); - printf("Table \"%.*s\":\n", (int)name_length, name); - print_schema_meta_fields(meta, indent + 1); - printf("\n"); - print_schema_meta_entries(meta, indent + 1); - break; + print_meta_fields(cass_iterator_fields_from_table_meta(meta), indent + 1); + printf("\n"); - case CASS_SCHEMA_META_TYPE_COLUMN: - field = cass_schema_meta_get_field(meta, "column_name"); - cass_value_get_string(cass_schema_meta_field_value(field), &name, &name_length); - printf("Column \"%.*s\":\n", (int)name_length, name); - print_schema_meta_fields(meta, indent + 1); - printf("\n"); - break; + iterator = cass_iterator_columns_from_table_meta(meta); + while (cass_iterator_next(iterator)) { + print_column_meta(cass_iterator_get_column_meta(iterator), indent + 1); } + printf("\n"); + + cass_iterator_free(iterator); } + +void print_column_meta(const CassColumnMeta* meta, int indent) { + const char* name; + size_t name_length; + + print_indent(indent); + cass_column_meta_name(meta, &name, &name_length); + printf("Column \"%.*s\":\n", (int)name_length, name); + print_meta_fields(cass_iterator_fields_from_column_meta(meta), indent + 1); + printf("\n"); +} + diff --git a/examples/udt/udt.c b/examples/udt/udt.c index fa89e29a4..27ab51d02 100644 --- a/examples/udt/udt.c +++ b/examples/udt/udt.c @@ -33,7 +33,7 @@ #include "cassandra.h" CassUuidGen* uuid_gen; -const CassSchema* schema; +const CassSchemaMeta* schema_meta; void print_error(CassFuture* future) { const char* message; @@ -88,6 +88,7 @@ CassError insert_into_udt(CassSession* session) { CassUuid id; char id_str[CASS_UUID_STRING_LENGTH]; + const CassKeyspaceMeta* keyspace_meta = NULL; const CassDataType* udt_address = NULL; const CassDataType* udt_phone = NULL; @@ -98,8 +99,11 @@ CassError insert_into_udt(CassSession* session) { cass_uuid_gen_time(uuid_gen, &id); cass_uuid_string(id, id_str); - udt_address = cass_schema_get_udt(schema, "examples", "address"); - udt_phone = cass_schema_get_udt(schema, "examples", "phone_numbers"); + keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta, "examples"); + if (keyspace_meta != NULL) { + udt_address = cass_keyspace_meta_type_by_name(keyspace_meta, "address"); + udt_phone = cass_keyspace_meta_type_by_name(keyspace_meta, "phone_numbers"); + } if (udt_address != NULL && udt_phone != NULL) { int i; @@ -240,7 +244,7 @@ int main() { return -1; } - schema = cass_session_get_schema(session); + schema_meta = cass_session_get_schema_meta(session); execute_query(session, "CREATE KEYSPACE examples WITH replication = { \ @@ -266,7 +270,7 @@ int main() { cass_session_free(session); cass_uuid_gen_free(uuid_gen); - cass_schema_free(schema); + cass_schema_meta_free(schema_meta); return 0; } diff --git a/include/cassandra.h b/include/cassandra.h index 61faa2159..49353dfec 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -315,26 +315,23 @@ typedef struct CassUserType_ CassUserType; */ typedef struct CassSsl_ CassSsl; -/** - * @struct CassSchema - * - * A snapshot of the cluster's schema metadata. - */ -typedef struct CassSchema_ CassSchema; - /** * @struct CassSchemaMeta * - * Table/Column schema metdata. + * A snapshot of the schema's metadata. */ typedef struct CassSchemaMeta_ CassSchemaMeta; +typedef struct CassKeyspaceMeta_ CassKeyspaceMeta; +typedef struct CassTableMeta_ CassTableMeta; +typedef struct CassColumnMeta_ CassColumnMeta; +typedef struct CassMetaField_ CassMetaField; -/** - * @struct CassSchemaMetaField - * - * Key/Value metadata field for a keyspace, table or column. - */ -typedef struct CassSchemaMetaField_ CassSchemaMetaField; +typedef enum CassColumnType_ { + CASS_COLUMN_TYPE_REGULAR, + CASS_COLUMN_TYPE_PARTITION_KEY, + CASS_COLUMN_TYPE_CLUSTERING_KEY, + CASS_COLUMN_TYPE_STATIC +} CassColumnType; /** * @struct CassUuidGen @@ -501,18 +498,15 @@ typedef enum CassIteratorType_ { CASS_ITERATOR_TYPE_ROW, CASS_ITERATOR_TYPE_COLLECTION, CASS_ITERATOR_TYPE_MAP, - CASS_ITERATOR_TYPE_SCHEMA_META, - CASS_ITERATOR_TYPE_SCHEMA_META_FIELD, CASS_ITERATOR_TYPE_TUPLE, - CASS_ITERATOR_TYPE_USER_TYPE + CASS_ITERATOR_TYPE_USER_TYPE, + CASS_ITERATOR_TYPE_META_FIELD, + CASS_ITERATOR_TYPE_KEYSPACE_META, + CASS_ITERATOR_TYPE_TABLE_META, + CASS_ITERATOR_TYPE_TYPE_META, + CASS_ITERATOR_TYPE_COLUMN_META } CassIteratorType; -typedef enum CassSchemaMetaType_ { - CASS_SCHEMA_META_TYPE_KEYSPACE, - CASS_SCHEMA_META_TYPE_TABLE, - CASS_SCHEMA_META_TYPE_COLUMN -} CassSchemaMetaType; - #define CASS_LOG_LEVEL_MAP(XX) \ XX(CASS_LOG_DISABLED, "") \ XX(CASS_LOG_CRITICAL, "CRITICAL") \ @@ -1489,8 +1483,8 @@ cass_session_execute_batch(CassSession* session, const CassBatch* batch); /** - * Gets a copy of this session's schema metadata. The returned - * copy of the schema metadata is not updated. This function + * Gets a snapshot of this session's schema metadata. The returned + * snapshot of the schema metadata is not updated. This function * must be called again to retrieve any schema changes since the * previous call. * @@ -1501,8 +1495,8 @@ cass_session_execute_batch(CassSession* session, * * @see cass_schema_free() */ -CASS_EXPORT const CassSchema* -cass_session_get_schema(const CassSession* session); +CASS_EXPORT const CassSchemaMeta* +cass_session_get_schema_meta(const CassSession* session); /** * Gets a copy of this session's performance/diagnostic metrics. @@ -1520,198 +1514,423 @@ cass_session_get_metrics(const CassSession* session, /*********************************************************************************** * - * Schema metadata + * Schema Metadata * ***********************************************************************************/ /** - * Frees a schema instance. + * Frees a schema metadata instance. * - * @public @memberof CassSchema + * @public @memberof CassSchemaMeta * - * @param[in] schema + * @param[in] schema_meta */ CASS_EXPORT void -cass_schema_free(const CassSchema* schema); +cass_schema_meta_free(const CassSchemaMeta* schema_meta); + +/** + * Gets the version of the schema metadata snapshot. + * + * @public @memberof CassSchemaMeta + * + * @param[in] schema_meta + */ +CASS_EXPORT cass_uint32_t +cass_schema_meta_version(const CassSchemaMeta* schema_meta); /** - * Gets the metadata for the provided keyspace name. + * Gets the keyspace metadata for the provided keyspace name. * - * @public @memberof CassSchema + * @public @memberof CassSchemaMeta * - * @param[in] schema + * @param[in] schema_meta * @param[in] keyspace - * @return The schema metadata for a keyspace. NULL if keyspace does not exist. * - * @see cass_schema_meta_get_entry() - * @see cass_schema_meta_get_field() - * @see cass_schema_meta_type() - * @see cass_iterator_from_schema_meta() + * @return The metadata for a keyspace. NULL if keyspace does not exist. */ -CASS_EXPORT const CassSchemaMeta* -cass_schema_get_keyspace(const CassSchema* schema, - const char* keyspace); +CASS_EXPORT const CassKeyspaceMeta* +cass_schema_meta_keyspace_by_name(const CassSchemaMeta* schema_meta, + const char* keyspace); /** - * Same as cass_schema_get_keyspace(), but with lengths for string + * Same as cass_schema_meta_keyspace_by_name(), but with lengths for string * parameters. * - * @public @memberof CassSchema + * @public @memberof CassSchemaMeta * - * @param[in] schema + * @param[in] schema_meta * @param[in] keyspace * @param[in] keyspace_length - * @return same as cass_schema_get_keyspace() + * @return same as cass_schema_meta_keyspace_by_name() * - * @see cass_schema_get_keyspace() + * @see cass_schema_meta_keyspace_by_name() */ -CASS_EXPORT const CassSchemaMeta* -cass_schema_get_keyspace_n(const CassSchema* schema, - const char* keyspace, - size_t keyspace_length); +CASS_EXPORT const CassKeyspaceMeta* +cass_schema_meta_keyspace_by_name_n(const CassSchemaMeta* schema_meta, + const char* keyspace, + size_t keyspace_length); /** - * Gets a UDT data type + * Gets the table metadata for the provided table name. * - * @public @memberof CassSchema + * @public @memberof CassKeyspaceMeta * - * @param[in] schema - * @param[in] keyspace - * @param[in] type_name - * @return Returns a reference to the data type of the parameter. Do not free - * this reference as it is bound to the lifetime of the schema. + * @param[in] keyspace_meta + * @param[in] table + * + * @return The metadata for a table. NULL if table does not exist. */ -CASS_EXPORT const CassDataType* -cass_schema_get_udt(const CassSchema* schema, - const char* keyspace, - const char* type_name); +CASS_EXPORT const CassTableMeta* +cass_keyspace_meta_table_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* table); /** - * Same as cass_schema_get_udt(), but with lengths for string + * Same as cass_keyspace_meta_table_by_name(), but with lengths for string * parameters. * - * @public @memberof CassSchema + * @public @memberof CassKeyspaceMeta * - * @param[in] schema - * @param[in] keyspace - * @param[in] keyspace_length - * @param[in] type_name - * @param[in] type_name_length - * @return Returns a reference to the data type of the parameter. Do not free - * this reference as it is bound to the lifetime of the schema. + * @param[in] keyspace_meta + * @param[in] table + * @param[in] table_length + * @return same as cass_keyspace_meta_table_by_name() + * + * @see cass_keyspace_meta_table_by_name() + */ +CASS_EXPORT const CassTableMeta* +cass_keyspace_meta_table_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* table, + size_t table_length); + + +/** + * Gets the data type for the provided type name. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] type + * + * @return The data type for a user defined type. NULL if type does not exist. */ CASS_EXPORT const CassDataType* -cass_schema_get_udt_n(const CassSchema* schema, - const char* keyspace, - size_t keyspace_length, - const char* type_name, - size_t type_name_length); +cass_keyspace_meta_type_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* type); /** - * Gets the type of the specified schema metadata. + * Same as cass_keyspace_meta_type_by_name(), but with lengths for string + * parameters. * - * @public @memberof CassSchema + * @public @memberof CassKeyspaceMeta * - * @param[in] meta - * @return The type of the schema metadata + * @param[in] keyspace_meta + * @param[in] type + * @param[in] type_length + * @return same as cass_keyspace_meta_type_by_name() + * + * @see cass_keyspace_meta_type_by_name() */ -CASS_EXPORT CassSchemaMetaType -cass_schema_meta_type(const CassSchemaMeta* meta); +CASS_EXPORT const CassDataType* +cass_keyspace_meta_type_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* type, + size_t type_length); /** - * Gets a metadata entry for the provided table/column name. + * Gets the name of the keyspace. * - * @public @memberof CassSchemaMeta + * @public @memberof CassKeyspaceMeta * - * @param[in] meta - * @param[in] name The name of a table or column - * @return The schema metadata for a table/column. NULL if table/column does not exist. + * @param[in] keyspace_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_keyspace_meta_name(const CassKeyspaceMeta* keyspace_meta, + const char** name, + size_t* name_length); + +/** + * Gets a metadata field for the provided name. + * + * @public @memberof CassKeyspaceMeta * - * @see cass_schema_meta_get_entry() - * @see cass_schema_meta_get_field() - * @see cass_schema_meta_type() - * @see cass_iterator_from_schema_meta() - * @see cass_iterator_fields_from_schema_meta() + * @param[in] keyspace_meta + * @param[in] name + * @return A schema metadata field. NULL if the field does not exist. */ -CASS_EXPORT const CassSchemaMeta* -cass_schema_meta_get_entry(const CassSchemaMeta* meta, - const char* name); +CASS_EXPORT const CassMetaField* +cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name); /** - * Same as cass_schema_meta_get_entry(), but with lengths for string + * Same as cass_keyspace_meta_field_by_name(), but with lengths for string * parameters. * - * @public @memberof CassSchema + * @public @memberof CassKeyspaceMeta * - * @param[in] meta + * @param[in] keyspace_meta * @param[in] name * @param[in] name_length - * @return same as cass_schema_meta_get_entry() + * @return same as cass_keyspace_meta_field_by_name() * - * @see cass_schema_meta_get_entry() + * @see cass_keyspace_meta_field_by_name() */ -CASS_EXPORT const CassSchemaMeta* -cass_schema_meta_get_entry_n(const CassSchemaMeta* meta, - const char* name, - size_t name_length); +CASS_EXPORT const CassMetaField* +cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, + size_t name_length); + +/** + * Gets the column metadata for the provided column name. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] column + * + * @return The metadata for a column. NULL if column does not exist. + */ +CASS_EXPORT const CassColumnMeta* +cass_table_meta_column_by_name(const CassTableMeta* table_meta, + const char* column); + +/** + * Same as cass_table_meta_column_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] column + * @param[in] column_length + * @return same as cass_table_meta_column_by_name() + * + * @see cass_table_meta_column_by_name() + */ +CASS_EXPORT const CassColumnMeta* +cass_table_meta_column_by_name_n(const CassTableMeta* table_meta, + const char* column, + size_t column_length); + +/** + * Gets the name of the table. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_table_meta_name(const CassTableMeta* table_meta, + const char** name, + size_t* name_length); + +/** + * Gets the id of the table. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return The UUID id of the table. + */ +CASS_EXPORT CassUuid +cass_table_meta_id(const CassTableMeta* table_meta); + +/** + * Gets the total number of columns for the table. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return The total column count. + */ +CASS_EXPORT size_t +cass_table_meta_column_count(const CassTableMeta* table_meta); + +/** + * Gets the column metadata for the provided index. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] index + * @return The metadata for a column. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassColumnMeta* +cass_table_meta_column(const CassTableMeta* table_meta, + size_t index); + +/** + * Gets the number of columns for the table's paritition key. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return The count for the number of columns in the partition key. + */ +CASS_EXPORT size_t +cass_table_meta_partition_key_count(const CassTableMeta* table_meta); + +/** + * Gets the partition key column metadata for the provided index. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] index + * @return The metadata for a column. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassColumnMeta* +cass_table_meta_partition_key(const CassTableMeta* table_meta, + size_t index); + +/** + * Gets the number of columns for the table's clustering key. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return The count for the number of columns in the clustering key. + */ +CASS_EXPORT size_t +cass_table_meta_clustering_key_count(const CassTableMeta* table_meta); + +/** + * Gets the clustering key column metadata for the provided index. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] index + * @return The metadata for a column. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassColumnMeta* +cass_table_meta_clustering_key(const CassTableMeta* table_meta, + size_t index); /** * Gets a metadata field for the provided name. * - * @public @memberof CassSchemaMeta + * @public @memberof CassTableMeta * - * @param[in] meta - * @param[in] name The name of a field + * @param[in] table_meta + * @param[in] name * @return A schema metadata field. NULL if the field does not exist. + */ +CASS_EXPORT const CassMetaField* +cass_table_meta_field_by_name(const CassTableMeta* table_meta, + const char* name); + +/** + * Same as cass_table_meta_field_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] name + * @param[in] name_length + * @return same as cass_table_meta_field_by_name() + * + * @see cass_table_meta_field_by_name() + */ +CASS_EXPORT const CassMetaField* +cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, + const char* name, + size_t name_length); + +/** + * Gets the name of the column. + * + * @public @memberof CassColumnMeta + * + * @param[in] column_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_column_meta_name(const CassColumnMeta* column_meta, + const char** name, + size_t* name_length); + +/** + * Gets the type of the column. + * + * @public @memberof CassColumnMeta + * + * @param[in] column_meta + * @return The column's type. + */ +CASS_EXPORT CassColumnType +cass_column_meta_type(const CassColumnMeta* column_meta); + +/** + * Gets the data type of the column. + * + * @public @memberof CassColumnMeta * - * @see cass_schema_meta_field_value() + * @param[in] column_meta + * @return The column's data type. */ -CASS_EXPORT const CassSchemaMetaField* -cass_schema_meta_get_field(const CassSchemaMeta* meta, - const char* name); +CASS_EXPORT CassDataType* +cass_column_meta_data_type(const CassColumnMeta* column_meta); /** - * Same as cass_schema_meta_get_field(), but with lengths for string + * Gets a metadata field for the provided name. + * + * @public @memberof CassColumnMeta + * + * @param[in] column_meta + * @param[in] name + * @return A schema metadata field. NULL if the field does not exist. + */ +CASS_EXPORT const CassMetaField* +cass_column_meta_field_by_name(const CassColumnMeta* column_meta, + const char* name); + +/** + * Same as cass_column_meta_field_by_name(), but with lengths for string * parameters. * - * @public @memberof CassSchema + * @public @memberof CassColumnMeta * - * @param[in] meta + * @param[in] column_meta * @param[in] name * @param[in] name_length - * @return same as cass_schema_meta_get_field() + * @return same as cass_column_meta_field_by_name() * - * @see cass_schema_meta_get_field() + * @see cass_column_meta_field_by_name() */ -CASS_EXPORT const CassSchemaMetaField* -cass_schema_meta_get_field_n(const CassSchemaMeta* meta, - const char* name, - size_t name_length); +CASS_EXPORT const CassMetaField* +cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, + const char* name, + size_t name_length); /** - * Gets the name for a schema metadata field + * Gets the name for a metadata field * - * @public @memberof CassSchemaMetaField + * @public @memberof CassMetaField * * @param[in] field * @param[out] name The name of the metadata data field * @param[out] name_length */ CASS_EXPORT void -cass_schema_meta_field_name(const CassSchemaMetaField* field, - const char** name, - size_t* name_length); +cass_meta_field_name(const CassMetaField* field, + const char** name, + size_t* name_length); /** - * Gets the value for a schema metadata field + * Gets the value for a metadata field * - * @public @memberof CassSchemaMetaField + * @public @memberof CassMetaField * * @param[in] field * @return The value of the metadata data field */ CASS_EXPORT const CassValue* -cass_schema_meta_field_value(const CassSchemaMetaField* field); +cass_meta_field_value(const CassMetaField* field); /*********************************************************************************** * @@ -5822,49 +6041,109 @@ CASS_EXPORT CassIterator* cass_iterator_from_user_type(const CassValue* value); /** - * Creates a new iterator for the specified schema. - * This can be used to iterate over keyspace entries. + * Creates a new iterator for the specified schema metadata. + * This can be used to iterate over keyspace. + * + * @public @memberof CassSchemaMeta + * + * @param[in] schema_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_keyspace_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta); + +/** + * Creates a new iterator for the specified keyspace metadata. + * This can be used to iterate over tables. * - * @public @memberof CassSchema + * @public @memberof CassKeyspaceMeta * - * @param[in] schema + * @param[in] keyspace_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_schema_meta() + * @see cass_iterator_get_table_meta() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_from_schema(const CassSchema* schema); +cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); /** - * Creates a new iterator for the specified schema metadata. - * This can be used to iterate over table/column entries. + * Creates a new iterator for the specified keyspace metadata. + * This can be used to iterate over types. * - * @public @memberof CassSchemaMeta + * @public @memberof CassKeyspaceMeta * - * @param[in] meta + * @param[in] keyspace_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_schema_meta() + * @see cass_iterator_get_type_meta() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_from_schema_meta(const CassSchemaMeta* meta); +cass_iterator_types_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); /** - * Creates a new iterator for the specified schema metadata. - * This can be used to iterate over schema metadata fields. + * Creates a new iterator for the specified keyspace metadata. + * This can be used to iterate over field entries. * - * @public @memberof CassSchemaMeta + * @public @memberof CassKeyspaceMeta * - * @param[in] meta + * @param[in] keyspace_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_schema_meta_field() + * @see cass_iterator_get_meta_field() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_fields_from_schema_meta(const CassSchemaMeta* meta); +cass_iterator_fields_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); + +/** + * Creates a new iterator for the specified table metadata. + * This can be used to iterate over columns. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_column_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta); + +/** + * Creates a new iterator for the specified table metadata. + * This can be used to iterate over field entries. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_meta_field() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta); + +/** + * Creates a new iterator for the specified column metadata. + * This can be used to iterate over field entries. + * + * @public @memberof CassColumnMeta + * + * @param[in] column_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_meta_field() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_fields_from_column_meta(const CassColumnMeta* column_meta); /** * Advance the iterator to the next row, column or collection item. @@ -5981,8 +6260,7 @@ CASS_EXPORT const CassValue* cass_iterator_get_user_type_field_value(CassIterator* iterator); /** - * Gets the schema metadata entry at the iterator's current - * position. + * Gets the keyspace metadata entry at the iterator's current position. * * Calling cass_iterator_next() will invalidate the previous * value returned by this method. @@ -5990,14 +6268,13 @@ cass_iterator_get_user_type_field_value(CassIterator* iterator); * @public @memberof CassIterator * * @param[in] iterator - * @return A keyspace/table/column schema metadata entry + * @return A keyspace metadata entry */ -CASS_EXPORT const CassSchemaMeta* -cass_iterator_get_schema_meta(CassIterator* iterator); +CASS_EXPORT const CassKeyspaceMeta* +cass_iterator_get_keyspace_meta(const CassIterator* iterator); /** - * Gets the schema metadata field at the iterator's current - * position. + * Gets the table metadata entry at the iterator's current position. * * Calling cass_iterator_next() will invalidate the previous * value returned by this method. @@ -6005,10 +6282,53 @@ cass_iterator_get_schema_meta(CassIterator* iterator); * @public @memberof CassIterator * * @param[in] iterator - * @return A schema metadata field + * @return A table metadata entry */ -CASS_EXPORT const CassSchemaMetaField* -cass_iterator_get_schema_meta_field(CassIterator* iterator); +CASS_EXPORT const CassTableMeta* +cass_iterator_get_table_meta(const CassIterator* iterator); + +/** + * Gets the type metadata entry at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A type metadata entry + */ +CASS_EXPORT const CassDataType* +cass_iterator_get_type_meta(const CassIterator* iterator); + +/** + * Gets the column metadata entry at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A column metadata entry + */ +CASS_EXPORT const CassColumnMeta* +cass_iterator_get_column_meta(const CassIterator* iterator); + +/** + * Gets the metadata field entry at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A metadata field + */ +CASS_EXPORT const CassMetaField* +cass_iterator_get_meta_field(const CassIterator* iterator); + /*********************************************************************************** * diff --git a/src/control_connection.cpp b/src/control_connection.cpp index 0258316fe..7b94a7245 100644 --- a/src/control_connection.cpp +++ b/src/control_connection.cpp @@ -101,7 +101,7 @@ ControlConnection::ControlConnection() , session_(NULL) , connection_(NULL) , protocol_version_(0) - , query_tokens_(false) {} + , should_query_tokens_(false) {} const SharedRefPtr ControlConnection::connected_host() const { return session_->get_host(current_host_address_); @@ -115,14 +115,14 @@ void ControlConnection::clear() { query_plan_.reset(); protocol_version_ = 0; last_connection_error_.clear(); - query_tokens_ = false; + should_query_tokens_ = false; } void ControlConnection::connect(Session* session) { session_ = session; query_plan_.reset(new ControlStartupQueryPlan(session_->hosts_)); // No hosts lock necessary (read-only) protocol_version_ = session_->config().protocol_version(); - query_tokens_ = session_->config().token_aware_routing(); + should_query_tokens_ = session_->config().token_aware_routing(); if (protocol_version_ < 0) { protocol_version_ = CASS_HIGHEST_SUPPORTED_PROTOCOL_VERSION; } @@ -340,7 +340,7 @@ void ControlConnection::on_event(EventResponse* response) { } } -//TODO: query and callbacks should be in ClusterMetadata +//TODO: query and callbacks should be in Metadata // punting for now because of tight coupling of Session and CC state void ControlConnection::query_meta_all() { ScopedRefPtr > handler( @@ -368,7 +368,7 @@ void ControlConnection::on_query_meta_all(ControlConnection* control_connection, Session* session = control_connection->session_; - session->metadata().clear(); + session->metadata().clear_and_update_back(); bool is_initial_connection = (control_connection->state_ == CONTROL_STATE_NEW); @@ -442,7 +442,8 @@ void ControlConnection::on_query_meta_all(ControlConnection* control_connection, if (control_connection->protocol_version_ >= 3) { session->metadata().update_types(static_cast(responses[5].get())); } - session->metadata().build(); + + session->metadata().swap_to_back_and_update_front(); } if (is_initial_connection) { @@ -466,7 +467,7 @@ void ControlConnection::refresh_node_info(SharedRefPtr host, std::string query; ControlHandler::ResponseCallback response_callback; - bool token_query = query_tokens_ && (host->was_just_added() || query_tokens); + bool token_query = should_query_tokens_ && (host->was_just_added() || query_tokens); if (is_connected_host || !host->listen_address().empty()) { if (is_connected_host) { query.assign(token_query ? SELECT_LOCAL_TOKENS : SELECT_LOCAL); @@ -594,7 +595,7 @@ void ControlConnection::update_node_info(SharedRefPtr host, const Row* row } } - if (query_tokens_) { + if (should_query_tokens_) { std::string partitioner; if (row->get_string_by_name("partitioner", &partitioner)) { session_->metadata().set_partitioner(partitioner); diff --git a/src/control_connection.hpp b/src/control_connection.hpp index 79bad9b8b..3c3dd3c73 100644 --- a/src/control_connection.hpp +++ b/src/control_connection.hpp @@ -210,7 +210,7 @@ class ControlConnection : public Connection::Listener { Address current_host_address_; int protocol_version_; std::string last_connection_error_; - bool query_tokens_; + bool should_query_tokens_; static Address bind_any_ipv4_; static Address bind_any_ipv6_; diff --git a/src/external_types.hpp b/src/external_types.hpp index 76c695676..398e014d3 100644 --- a/src/external_types.hpp +++ b/src/external_types.hpp @@ -71,9 +71,11 @@ EXTERNAL_TYPE(cass::Iterator, CassIterator); EXTERNAL_TYPE(cass::Row, CassRow); EXTERNAL_TYPE(cass::Value, CassValue); EXTERNAL_TYPE(cass::SslContext, CassSsl); -EXTERNAL_TYPE(cass::Metadata::Snapshot, CassSchema); -EXTERNAL_TYPE(cass::SchemaMetadata, CassSchemaMeta); -EXTERNAL_TYPE(cass::SchemaMetadataField, CassSchemaMetaField); +EXTERNAL_TYPE(cass::Metadata::SchemaSnapshot, CassSchemaMeta); +EXTERNAL_TYPE(cass::MetadataField, CassMetaField); +EXTERNAL_TYPE(cass::KeyspaceMetadata, CassKeyspaceMeta); +EXTERNAL_TYPE(cass::TableMetadata, CassTableMeta); +EXTERNAL_TYPE(cass::ColumnMetadata, CassColumnMeta); EXTERNAL_TYPE(cass::UuidGen, CassUuidGen); EXTERNAL_TYPE(cass::Tuple, CassTuple); EXTERNAL_TYPE(cass::UserTypeValue, CassUserType); diff --git a/src/future.cpp b/src/future.cpp index b6ff6cbcb..5e453e756 100644 --- a/src/future.cpp +++ b/src/future.cpp @@ -81,9 +81,9 @@ const CassPrepared* cass_future_get_prepared(CassFuture* future) { cass::SharedRefPtr result(response_future->response()); if (result && result->kind() == CASS_RESULT_KIND_PREPARED) { std::vector key_aliases; - response_future->snapshot->get_table_key_columns(result->keyspace().to_string(), - result->table().to_string(), - &key_aliases); + response_future->schema_metadata.get_table_key_columns(result->keyspace().to_string(), + result->table().to_string(), + &key_aliases); cass::Prepared* prepared = new cass::Prepared(result, response_future->statement, key_aliases); prepared->inc_ref(); diff --git a/src/metadata.cpp b/src/metadata.cpp index f6a348849..c4299cdf6 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -26,6 +26,7 @@ #include "row.hpp" #include "row_iterator.hpp" #include "scoped_lock.hpp" +#include "type_parser.hpp" #include "value.hpp" #include "third_party/rapidjson/rapidjson/document.h" @@ -34,358 +35,409 @@ extern "C" { -void cass_schema_free(const CassSchema* schema) { - delete schema->from(); +void cass_schema_meta_free(const CassSchemaMeta* schema_meta) { + delete schema_meta->from(); } -const CassSchemaMeta* cass_schema_get_keyspace(const CassSchema* schema, +cass_uint32_t cass_schema_meta_version(const CassSchemaMeta* schema_meta) { + return schema_meta->version(); +} + +const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name(const CassSchemaMeta* schema_meta, const char* keyspace) { - return cass_schema_get_keyspace_n(schema, keyspace, strlen(keyspace)); + return CassKeyspaceMeta::to(schema_meta->get_keyspace(keyspace)); } -const CassSchemaMeta* cass_schema_get_keyspace_n(const CassSchema* schema, +const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name_n(const CassSchemaMeta* schema_meta, const char* keyspace, size_t keyspace_length) { - return CassSchemaMeta::to(schema->get_keyspace(std::string(keyspace, keyspace_length))); + return CassKeyspaceMeta::to(schema_meta->get_keyspace(std::string(keyspace, keyspace_length))); } -CassSchemaMetaType cass_schema_meta_type(const CassSchemaMeta* meta) { - return meta->type(); +const CassTableMeta* cass_keyspace_meta_table_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* table) { + return CassTableMeta::to(keyspace_meta->get_table(table)); } -const CassDataType* cass_schema_get_udt(const CassSchema* schema, - const char* keyspace, - const char* type_name) { - return cass_schema_get_udt_n(schema, - keyspace, strlen(keyspace), - type_name, strlen(type_name)); +const CassTableMeta* cass_keyspace_meta_table_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* table, + size_t table_length) { + + return CassTableMeta::to(keyspace_meta->get_table(std::string(table, table_length))); } -const CassDataType* cass_schema_get_udt_n(const CassSchema* schema, - const char* keyspace, - size_t keyspace_length, - const char* type_name, - size_t type_name_length) { - std::string keyspace_id(keyspace, keyspace_length); - std::string type_name_id(type_name, type_name_length); - cass::SharedRefPtr user_type - = schema->get_type(cass::to_cql_id(keyspace_id), - cass::to_cql_id(type_name_id)); - return CassDataType::to(user_type.get()); +const CassDataType* cass_keyspace_meta_type_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* type) { + return CassDataType::to(keyspace_meta->get_type(type)); } -const CassSchemaMeta* cass_schema_meta_get_entry(const CassSchemaMeta* meta, - const char* name) { - return cass_schema_meta_get_entry_n(meta, name, strlen(name)); +const CassDataType* cass_keyspace_meta_type_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* type, + size_t type_length) { + return CassDataType::to(keyspace_meta->get_type(std::string(type, type_length))); } -const CassSchemaMeta* cass_schema_meta_get_entry_n(const CassSchemaMeta* meta, - const char* name, - size_t name_length) { - return CassSchemaMeta::to(meta->get_entry(std::string(name, name_length))); +void cass_keyspace_meta_name(const CassKeyspaceMeta* keyspace_meta, + const char** name, size_t* name_length) { + *name = keyspace_meta->name().data(); + *name_length = keyspace_meta->name().size(); } -const CassSchemaMetaField* cass_schema_meta_get_field(const CassSchemaMeta* meta, - const char* name) { - return cass_schema_meta_get_field_n(meta, name, strlen(name)); +const CassMetaField* cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name) { + return CassMetaField::to(keyspace_meta->get_field(name)); } -const CassSchemaMetaField* cass_schema_meta_get_field_n(const CassSchemaMeta* meta, - const char* name, - size_t name_length) { - return CassSchemaMetaField::to(meta->get_field(std::string(name, name_length))); +const CassMetaField* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, size_t name_length) { + return CassMetaField::to(keyspace_meta->get_field(std::string(name, name_length))); } -void cass_schema_meta_field_name(const CassSchemaMetaField* field, - const char** name, - size_t* name_length) { - const std::string& n = field->name(); - *name = n.data(); - *name_length = n.length(); + +const CassColumnMeta* cass_table_meta_column_by_name(const CassTableMeta* table_meta, + const char* column) { + return CassColumnMeta::to(table_meta->get_column(column)); } -const CassValue* cass_schema_meta_field_value(const CassSchemaMetaField* field) { - return CassValue::to(field->value()); +const CassColumnMeta* cass_table_meta_column_by_name_n(const CassTableMeta* table_meta, + const char* column, + size_t column_length) { + return CassColumnMeta::to(table_meta->get_column(std::string(column, column_length))); +} + +void cass_table_meta_name(const CassTableMeta* table_meta, + const char** name, size_t* name_length) { + *name = table_meta->name().data(); + *name_length = table_meta->name().size(); +} + +CassUuid cass_table_meta_id(const CassTableMeta* table_meta) { + return table_meta->id(); +} + +const CassMetaField* cass_table_meta_field_by_name(const CassTableMeta* table_meta, + const char* name) { + return CassMetaField::to(table_meta->get_field(name)); } -CassIterator* cass_iterator_from_schema(const CassSchema* schema) { - return CassIterator::to(schema->iterator()); +const CassMetaField* cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, + const char* name, size_t name_length) { + return CassMetaField::to(table_meta->get_field(std::string(name, name_length))); } -CassIterator* cass_iterator_from_schema_meta(const CassSchemaMeta* meta) { - return CassIterator::to(meta->iterator()); +size_t cass_table_meta_column_count(const CassTableMeta* table_meta) { + return table_meta->columns().size(); } -const CassSchemaMeta* cass_iterator_get_schema_meta(CassIterator* iterator) { - if (iterator->type() != CASS_ITERATOR_TYPE_SCHEMA_META) { +const CassColumnMeta* cass_table_meta_column(const CassTableMeta* table_meta, + size_t index) { + if (index >= table_meta->columns().size()) { return NULL; } - return CassSchemaMeta::to( - static_cast( - iterator->from())->meta()); + return CassColumnMeta::to(table_meta->columns()[index].get()); } -CassIterator* cass_iterator_fields_from_schema_meta(const CassSchemaMeta* meta) { - return CassIterator::to(meta->iterator_fields()); +size_t cass_table_meta_partition_key_count(const CassTableMeta* table_meta) { + return table_meta->partition_key().size(); } -const CassSchemaMetaField* cass_iterator_get_schema_meta_field(CassIterator* iterator) { - if (iterator->type() != CASS_ITERATOR_TYPE_SCHEMA_META_FIELD) { +const CassColumnMeta* cass_table_meta_partition_key(const CassTableMeta* table_meta, + size_t index) { + if (index >= table_meta->partition_key().size()) { return NULL; } - return CassSchemaMetaField::to( - static_cast( - iterator->from())->field()); + return CassColumnMeta::to(table_meta->partition_key()[index].get()); } -} // extern "C" +size_t cass_table_meta_clustering_key_count(const CassTableMeta* table_meta) { + return table_meta->clustering_key().size(); +} -namespace cass { +const CassColumnMeta* cass_table_meta_clustering_key(const CassTableMeta* table_meta, + size_t index) { + if (index >= table_meta->clustering_key().size()) { + return NULL; + } + return CassColumnMeta::to(table_meta->clustering_key()[index].get()); +} -template -const T& as_const(const T& x) { return x; } +void cass_column_meta_name(const CassColumnMeta* column_meta, + const char** name, size_t* name_length) { + *name = column_meta->name().data(); + *name_length = column_meta->name().size(); +} -template -const T* find_by_name(const std::map& map, const std::string& name) { - typename std::map::const_iterator it = map.find(name); - if (it == map.end()) return NULL; - return &it->second; +CassColumnType cass_column_meta_type(const CassColumnMeta* column_meta) { + return column_meta->type(); } -const SchemaMetadata* Metadata::Snapshot::get_keyspace(const std::string& name) const { - KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(name); - if (i == keyspaces_->end()) return NULL; - return i->second.get(); +CassDataType* cass_column_meta_data_type(const CassColumnMeta* column_meta) { + return CassDataType::to(column_meta->data_type().get()); } -SharedRefPtr Metadata::Snapshot::get_type(const std::string& keyspace_name, - const std::string& type_name) const -{ - KeyspaceMetadata::Map::const_iterator i = as_const(keyspaces_)->find(keyspace_name); - if (i == as_const(keyspaces_)->end()) { - return SharedRefPtr(); - } - return i->second->get_type(type_name); +cass_bool_t cass_column_meta_is_reversed(const CassColumnMeta* column_meta) { + return column_meta->is_reversed() ? cass_true : cass_false; } -Metadata::Snapshot* Metadata::snapshot() const { - ScopedMutex l(&mutex_); - return new Snapshot(snapshot_); +const CassMetaField* +cass_column_meta_field_by_name(const CassColumnMeta* column_meta, + const char* name) { + return CassMetaField::to(column_meta->get_field(name)); } -void Metadata::update_keyspaces(ResultResponse* result) { - ScopedMutex l(&mutex_); - KeyspacePointerMap updates; +const CassMetaField* +cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, + const char* name, size_t name_length) { + return CassMetaField::to(column_meta->get_field(std::string(name, name_length))); +} - SharedRefPtr buffer = result->buffer(); - result->decode_first_row(); - ResultIterator rows(result); +void cass_meta_field_name(const CassMetaField* field, + const char** name, size_t* name_length) { + const std::string& n = field->name(); + *name = n.data(); + *name_length = n.length(); +} - while (rows.next()) { - std::string keyspace_name; - const Row* row = rows.row(); +const CassValue* cass_meta_field_value(const CassMetaField* field) { + return CassValue::to(field->value()); +} - if (!row->get_string_by_name("keyspace_name", &keyspace_name)) { - LOG_ERROR("Unable to column value for 'keyspace_name'"); - continue; - } +CassIterator* cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta) { + return CassIterator::to(schema_meta->iterator_keyspaces()); +} - KeyspaceMetadata::Ptr keyspace = snapshot_.get_or_create_keyspace(keyspace_name); - keyspace->update(protocol_version_, buffer, row); - updates.insert(std::make_pair(keyspace_name, keyspace)); - } +CassIterator* cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_tables()); +} - for (KeyspacePointerMap::const_iterator i = updates.begin(); i != updates.end(); ++i) { - token_map_.update_keyspace(i->first, *i->second); - } +CassIterator* cass_iterator_types_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_types()); } -void Metadata::update_tables(ResultResponse* tables_result, ResultResponse* columns_result) { - ScopedMutex l(&mutex_); - SharedRefPtr buffer = tables_result->buffer(); +CassIterator* cass_iterator_fields_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_fields()); +} - tables_result->decode_first_row(); - ResultIterator rows(tables_result); +CassIterator* cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta) { + return CassIterator::to(table_meta->iterator_columns()); +} - std::string keyspace_name; - std::string columnfamily_name; - KeyspaceMetadata::Ptr keyspace; +CassIterator* cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta) { + return CassIterator::to(table_meta->iterator_fields()); +} - while (rows.next()) { - std::string temp_keyspace_name; - const Row* row = rows.row(); +CassIterator* cass_iterator_fields_from_column_meta(const CassColumnMeta* column_meta) { + return CassIterator::to(column_meta->iterator_fields()); +} - if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || - !row->get_string_by_name("columnfamily_name", &columnfamily_name)) { - LOG_ERROR("Unable to column value for 'keyspace_name' or 'columnfamily_name'"); - continue; - } +const CassKeyspaceMeta* cass_iterator_get_keyspace_meta(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_KEYSPACE_META) { + return NULL; + } + return CassKeyspaceMeta::to( + static_cast( + iterator->from())->keyspace()); +} - if (keyspace_name != temp_keyspace_name) { - keyspace_name = temp_keyspace_name; - keyspace = snapshot_.get_or_create_keyspace(keyspace_name); - } +const CassTableMeta* cass_iterator_get_table_meta(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_TABLE_META) { + return NULL; + } + return CassTableMeta::to( + static_cast( + iterator->from())->table()); +} - keyspace->get_or_create_table(columnfamily_name)->update(protocol_version_, buffer, row); +const CassDataType* cass_iterator_get_type_meta(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_TYPE_META) { + return NULL; } + return CassDataType::to( + static_cast( + iterator->from())->type()); +} - update_columns(columns_result); +const CassColumnMeta* cass_iterator_get_column_meta(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_COLUMN_META) { + return NULL; + } + return CassColumnMeta::to( + static_cast( + iterator->from())->column()); } -void Metadata::update_types(ResultResponse* result) { - ScopedMutex l(&mutex_); - result->decode_first_row(); - ResultIterator rows(result); +CASS_EXPORT const CassMetaField* +cass_iterator_get_meta_field(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_META_FIELD) { + return NULL; + } + return CassMetaField::to( + static_cast( + iterator->from())->field()); +} - while (rows.next()) { - std::string keyspace_name; - std::string type_name; - const Row* row = rows.row(); +} // extern "C" - if (!row->get_string_by_name("keyspace_name", &keyspace_name) || - !row->get_string_by_name("type_name", &type_name)) { - LOG_ERROR("Unable to column value for 'keyspace_name' or 'type_name'"); - continue; - } +namespace cass { - const Value* names_value = row->get_by_name("field_names"); - if (names_value == NULL || names_value->is_null()) { - LOG_ERROR("'field_name's column for keyspace \"%s\" and type \"%s\" is null", - keyspace_name.c_str(), type_name.c_str()); - continue; - } +template +const T& as_const(const T& x) { return x; } - const Value* types_value = row->get_by_name("field_types"); - if (types_value == NULL || types_value->is_null()) { - LOG_ERROR("'field_type's column for keyspace '%s' and type '%s' is null", - keyspace_name.c_str(), type_name.c_str()); - continue; - } +template +const T* find_by_name(const std::map& map, const std::string& name) { + typename std::map::const_iterator it = map.find(name); + if (it == map.end()) return NULL; + return it->second.get(); +} - CollectionIterator names(names_value); - CollectionIterator types(types_value); +const KeyspaceMetadata* Metadata::SchemaSnapshot::get_keyspace(const std::string& name) const { + KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(name); + if (i == keyspaces_->end()) return NULL; + return &i->second; +} - UserType::FieldVec fields; +const UserType* Metadata::SchemaSnapshot::get_type(const std::string& keyspace_name, + const std::string& type_name) const +{ + KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(keyspace_name); + if (i == keyspaces_->end()) { + return NULL; + } + return i->second.get_type(type_name); +} - while (names.next()) { - if(!types.next()) { - LOG_ERROR("The number of 'field_type's doesn\"t match the number of field_names for keyspace \"%s\" and type \"%s\"", - keyspace_name.c_str(), type_name.c_str()); - break; - } +Metadata::SchemaSnapshot Metadata::schema_snapshot() const { + ScopedMutex l(&mutex_); + return SchemaSnapshot(schema_snapshot_version_, front_.keyspaces()); +} - const cass::Value* name = names.value(); - const cass::Value* type = types.value(); +void Metadata::update_keyspaces(ResultResponse* result) { + KeyspaceMetadata::Map updates; - if (name->is_null() || type->is_null()) { - LOG_ERROR("'field_name' or 'field_type' is null for keyspace \"%s\" and type \"%s\"", - keyspace_name.c_str(), type_name.c_str()); - break; - } + schema_snapshot_version_++; - std::string field_name(name->to_string()); + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_keyspaces(protocol_version_, result, updates); + } else { + updating_->update_keyspaces(protocol_version_, result, updates); + } - SharedRefPtr data_type = TypeParser::parse_one(type->to_string()); - if (!data_type) { - LOG_ERROR("Invalid 'field_type' for field \"%s\", keyspace \"%s\" and type \"%s\"", - field_name.c_str(), - keyspace_name.c_str(), - type_name.c_str()); - break; - } + for (KeyspaceMetadata::Map::const_iterator i = updates.begin(); i != updates.end(); ++i) { + token_map_.update_keyspace(i->first, i->second); + } +} - fields.push_back(UserType::Field(field_name, data_type)); - } +void Metadata::update_tables(ResultResponse* tables_result, ResultResponse* columns_result) { + schema_snapshot_version_++; - snapshot_.get_or_create_keyspace(keyspace_name)->add_type( - SharedRefPtr(new UserType(keyspace_name, type_name, fields))); + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_tables(protocol_version_, tables_result, columns_result); + } else { + updating_->update_tables(protocol_version_, tables_result, columns_result); } } -void Metadata::update_columns(ResultResponse* result) { - // DO NOT LOCK: This is private and called from update_tables(). - - SharedRefPtr buffer = result->buffer(); +void Metadata::update_types(ResultResponse* result) { + schema_snapshot_version_++; - result->decode_first_row(); - ResultIterator rows(result); + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_types(result); + } else { + updating_->update_types(result); + } +} - std::string keyspace_name; - std::string columnfamily_name; - std::string column_name; - TableMetadata* table = NULL; - std::set cleared_tables; - while (rows.next()) { - std::string temp_keyspace_name; - std::string temp_columnfamily_name; - const Row* row = rows.row(); +void Metadata::drop_keyspace(const std::string& keyspace_name) { + schema_snapshot_version_++; - if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || - !row->get_string_by_name("columnfamily_name", &temp_columnfamily_name) || - !row->get_string_by_name("column_name", &column_name)) { - LOG_ERROR("Unable to column value for 'keyspace_name', 'columnfamily_name' or 'column_name'"); - continue; - } + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_keyspace(keyspace_name); + } else { + updating_->drop_keyspace(keyspace_name); + } +} - if (keyspace_name != temp_keyspace_name || - columnfamily_name != temp_columnfamily_name) { - keyspace_name = temp_keyspace_name; - columnfamily_name = temp_columnfamily_name; - table = snapshot_.get_or_create_keyspace(keyspace_name)->get_or_create_table(columnfamily_name); - if (cleared_tables.insert(table).second) { - table->clear_columns(); - } - } +void Metadata::drop_table(const std::string& keyspace_name, const std::string& table_name) { + schema_snapshot_version_++; - table->get_or_create(column_name)->update(protocol_version_, buffer, row); + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_table(keyspace_name, table_name); + } else { + updating_->drop_table(keyspace_name, table_name); } } -void Metadata::drop_keyspace(const std::string& keyspace_name) { - snapshot_.keyspaces_->erase(keyspace_name); +void Metadata::drop_type(const std::string& keyspace_name, const std::string& type_name) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_type(keyspace_name, type_name); + } else { + updating_->drop_type(keyspace_name, type_name); + } } -void Metadata::drop_table(const std::string& keyspace_name, const std::string& table_name) { - KeyspaceMetadata::Map::iterator it = snapshot_.keyspaces_->find(keyspace_name); - if (it == snapshot_.keyspaces_->end()) return; - it->second->drop_table(table_name); +void Metadata::clear_and_update_back() { + token_map_.clear(); + back_.clear(); + updating_ = &back_; } -void Metadata::drop_type(const std::string& keyspace_name, const std::string& type_name) { - KeyspaceMetadata::Map::iterator it = snapshot_.keyspaces_->find(keyspace_name); - if (it == snapshot_.keyspaces_->end()) return; - it->second->drop_type(type_name); +void Metadata::swap_to_back_and_update_front() { + { + ScopedMutex l(&mutex_); + schema_snapshot_version_++; + front_.swap(back_); + } + back_.clear(); + updating_ = &front_; + token_map_.build(); } void Metadata::clear() { - snapshot_.keyspaces_->clear(); + { + ScopedMutex l(&mutex_); + schema_snapshot_version_ = 0; + front_.clear(); + } + back_.clear(); + token_map_.clear(); } -const SchemaMetadataField* SchemaMetadata::get_field(const std::string& name) const { - return find_by_name(fields_, name); +const MetadataField* MetadataBase::get_field(const std::string& name) const { + typename MetadataField::Map::const_iterator it = fields_.find(name); + if (it == fields_.end()) return NULL; + return &it->second; } -std::string SchemaMetadata::get_string_field(const std::string& name) const { - const SchemaMetadataField* field = get_field(name); +std::string MetadataBase::get_string_field(const std::string& name) const { + const MetadataField* field = get_field(name); if (field == NULL) return std::string(); return field->value()->to_string(); } -void SchemaMetadata::add_field(const SharedRefPtr& buffer, const Row* row, const std::string& name) { +const Value* MetadataBase::add_field(const SharedRefPtr& buffer, const Row* row, const std::string& name) { const Value* value = row->get_by_name(name); - if (value == NULL) return; + if (value == NULL) return NULL; if (value->size() <= 0) { - fields_[name] = SchemaMetadataField(name); - return; + fields_[name] = MetadataField(name); + } else { + fields_[name] = MetadataField(name, *value, buffer); } - fields_[name] = SchemaMetadataField(name, *value, buffer); + return value; } -void SchemaMetadata::add_json_list_field(int version, const Row* row, const std::string& name) { +void MetadataBase::add_json_list_field(int version, const Row* row, const std::string& name) { const Value* value = row->get_by_name(name); if (value == NULL) return; if (value->size() <= 0) { - fields_[name] = SchemaMetadataField(name); + fields_[name] = MetadataField(name); return; } @@ -404,7 +456,7 @@ void SchemaMetadata::add_json_list_field(int version, const Row* row, const std: if (!d.IsArray()) { LOG_DEBUG("Expected JSON array for column '%s' (probably null or empty)", name.c_str()); - fields_[name] = SchemaMetadataField(name); + fields_[name] = MetadataField(name); return; } @@ -424,14 +476,14 @@ void SchemaMetadata::add_json_list_field(int version, const Row* row, const std: d.Size(), encoded->data(), encoded_size); - fields_[name] = SchemaMetadataField(name, list, encoded); + fields_[name] = MetadataField(name, list, encoded); } -void SchemaMetadata::add_json_map_field(int version, const Row* row, const std::string& name) { +void MetadataBase::add_json_map_field(int version, const Row* row, const std::string& name) { const Value* value = row->get_by_name(name); if (value == NULL) return; if (value->size() <= 0) { - fields_[name] = SchemaMetadataField(name); + fields_[name] = MetadataField(name); return; } @@ -450,12 +502,10 @@ void SchemaMetadata::add_json_map_field(int version, const Row* row, const std:: if (!d.IsObject()) { LOG_DEBUG("Expected JSON object for column '%s' (probably null or empty)", name.c_str()); - fields_[name] = SchemaMetadataField(name); + fields_[name] = MetadataField(name); return; } - - Collection collection(CollectionType::map(SharedRefPtr(new DataType(CASS_VALUE_TYPE_TEXT)), SharedRefPtr(new DataType(CASS_VALUE_TYPE_TEXT))), 2 * d.MemberCount()); @@ -474,19 +524,38 @@ void SchemaMetadata::add_json_map_field(int version, const Row* row, const std:: d.MemberCount(), encoded->data(), encoded_size); - fields_[name] = SchemaMetadataField(name, map, encoded); + fields_[name] = MetadataField(name, map, encoded); } -const SchemaMetadata* KeyspaceMetadata::get_entry(const std::string& name) const { - return find_by_name(tables_, name); +const TableMetadata* KeyspaceMetadata::get_table(const std::string& name) const { + TableMetadata::Map::const_iterator i = tables_->find(name); + if (i == tables_->end()) return NULL; + return i->second.get(); } -SharedRefPtr KeyspaceMetadata::get_type(const std::string& type_name) const { - UserTypeMap::const_iterator i = types_.find(type_name); - if (i == types_.end()) return SharedRefPtr(); +const TableMetadata::Ptr& KeyspaceMetadata::get_or_create_table(const std::string& name) { + TableMetadata::Map::iterator i = tables_->find(name); + if (i == tables_->end()) { + i = tables_->insert(std::make_pair(name, + TableMetadata::Ptr(new TableMetadata(name)))).first; + } return i->second; } +void KeyspaceMetadata::add_table(const TableMetadata::Ptr& table) { + (*tables_)[table->name()] = table; +} + +void KeyspaceMetadata::drop_table(const std::string& table_name) { + tables_->erase(table_name); +} + +const UserType* KeyspaceMetadata::get_type(const std::string& name) const { + TypeMap::const_iterator i = types_->find(name); + if (i == types_->end()) return NULL; + return i->second.get(); +} + void KeyspaceMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { add_field(buffer, row, "keyspace_name"); add_field(buffer, row, "durable_writes"); @@ -495,27 +564,29 @@ void KeyspaceMetadata::update(int version, const SharedRefPtr& buffer } void KeyspaceMetadata::add_type(const SharedRefPtr& user_type) { - types_[user_type->type_name()] = user_type; -} - -void KeyspaceMetadata::drop_table(const std::string& table_name) { - tables_.erase(table_name); + (*types_)[user_type->type_name()] = user_type; } void KeyspaceMetadata::drop_type(const std::string& type_name) { - types_.erase(type_name); + types_->erase(type_name); } -const SchemaMetadata* TableMetadata::get_entry(const std::string& name) const { - return find_by_name(columns_, name); -} +TableMetadata::TableMetadata(const std::string& name, + int version, const SharedRefPtr& buffer, const Row* row) + : MetadataBase(name) { + const Value* value; -void TableMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { add_field(buffer, row, "keyspace_name"); add_field(buffer, row, "columnfamily_name"); + + value = add_field(buffer, row, "cf_id"); + if (value != NULL && value->value_type() == CASS_VALUE_TYPE_UUID) { + id_ = value->as_uuid(); + } + add_field(buffer, row, "bloom_filter_fp_chance"); add_field(buffer, row, "caching"); - add_field(buffer, row, "cf_id"); + add_field(buffer, row, "id"); add_json_list_field(version, row, "column_aliases"); add_field(buffer, row, "comment"); add_field(buffer, row, "compaction_strategy_class"); @@ -527,7 +598,6 @@ void TableMetadata::update(int version, const SharedRefPtr& buffer, c add_field(buffer, row, "dropped_columns"); add_field(buffer, row, "gc_grace_seconds"); add_field(buffer, row, "index_interval"); - add_field(buffer, row, "id"); add_field(buffer, row, "is_dense"); add_field(buffer, row, "key_alias"); add_json_list_field(version, row, "key_aliases"); @@ -547,8 +617,63 @@ void TableMetadata::update(int version, const SharedRefPtr& buffer, c add_field(buffer, row, "value_alias"); } +const ColumnMetadata* TableMetadata::get_column(const std::string& name) const { + ColumnMetadata::Map::const_iterator i = columns_by_name_.find(name); + if (i == columns_by_name_.end()) return NULL; + return i->second.get(); +} + +const ColumnMetadata::Ptr& TableMetadata::get_or_create_column(const std::string& name) { + ColumnMetadata::Map::iterator i = columns_by_name_.find(name); + if (i == columns_by_name_.end()) { + ColumnMetadata::Ptr column(new ColumnMetadata(name)); + i = columns_by_name_.insert(std::make_pair(name, column)).first; + columns_.push_back(column); + } + return i->second; +} + +void TableMetadata::add_column(const ColumnMetadata::Ptr& column) { + columns_.push_back(column); + columns_by_name_[column->name()] = column; +} + +void TableMetadata::clear_columns() { + columns_.clear(); + columns_by_name_.clear(); + partition_key_.clear(); + clustering_key_.clear(); +} + +size_t get_column_count(const ColumnMetadata::Vec& columns, CassColumnType type) { + size_t count = 0; + for (ColumnMetadata::Vec::const_iterator i = columns.begin(), + end = columns.end(); i != end; ++i) { + if ((*i)->type() == type) count++; + } + return count; +} + +void TableMetadata::build_keys() { + partition_key_.resize(get_column_count(columns_, CASS_COLUMN_TYPE_PARTITION_KEY)); + clustering_key_.resize(get_column_count(columns_, CASS_COLUMN_TYPE_CLUSTERING_KEY)); + for (ColumnMetadata::Vec::const_iterator i = columns_.begin(), + end = columns_.end(); i != end; ++i) { + ColumnMetadata::Ptr column(*i); + if (column->type() == CASS_COLUMN_TYPE_PARTITION_KEY && + column->position() >= 0 && + static_cast(column->position()) < partition_key_.size()) { + partition_key_[column->position()] = column; + } else if (column->type() == CASS_COLUMN_TYPE_CLUSTERING_KEY && + column->position() >= 0 && + static_cast(column->position()) < clustering_key_.size()) { + clustering_key_[column->position()] = column; + } + } +} + void TableMetadata::key_aliases(KeyAliases* output) const { - const SchemaMetadataField* aliases = get_field("key_aliases"); + const MetadataField* aliases = get_field("key_aliases"); if (aliases != NULL) { output->reserve(aliases->value()->count()); CollectionIterator itr(aliases->value()); @@ -570,28 +695,238 @@ void TableMetadata::key_aliases(KeyAliases* output) const { } } -void ColumnMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { +ColumnMetadata::ColumnMetadata(const std::string& name, + int version, const SharedRefPtr& buffer, const Row* row) + : MetadataBase(name) { + const Value* value; + add_field(buffer, row, "keyspace_name"); add_field(buffer, row, "columnfamily_name"); add_field(buffer, row, "column_name"); - add_field(buffer, row, "type"); - add_field(buffer, row, "component_index"); - add_field(buffer, row, "validator"); + + value = add_field(buffer, row, "type"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + StringRef type = value->to_string_ref(); + if (type == "partition_key") { + type_ = CASS_COLUMN_TYPE_PARTITION_KEY; + } else if (type == "clustering_key") { + type_ = CASS_COLUMN_TYPE_CLUSTERING_KEY; + } else if (type == "static") { + type_ = CASS_COLUMN_TYPE_STATIC; + } else { + type_ = CASS_COLUMN_TYPE_REGULAR; + } + } + + value = add_field(buffer, row, "component_index"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_INT) { + position_ = value->as_int32(); + } + + value = add_field(buffer, row, "validator"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + std::string validator(value->to_string()); + data_type_ = TypeParser::parse_one(validator); + is_reversed_ = TypeParser::is_reversed(validator); + } + add_field(buffer, row, "index_name"); add_json_map_field(version, row, "index_options"); add_field(buffer, row, "index_type"); } -void Metadata::Snapshot::get_table_key_columns(const std::string& ks_name, - const std::string& table_name, - std::vector* output) const { - const SchemaMetadata* ks_meta = get_keyspace(ks_name); - if (ks_meta != NULL) { - const SchemaMetadata* table_meta = static_cast(ks_meta)->get_entry(table_name); - if (table_meta != NULL) { - static_cast(table_meta)->key_aliases(output); +void Metadata::SchemaSnapshot::get_table_key_columns(const std::string& ks_name, + const std::string& table_name, + std::vector* output) const { + const KeyspaceMetadata* keyspace = get_keyspace(ks_name); + if (keyspace != NULL) { + const TableMetadata* table = keyspace->get_table(table_name); + if (table != NULL) { + table->key_aliases(output); + } + } +} + +void Metadata::InternalData::update_keyspaces(int version, ResultResponse* result, KeyspaceMetadata::Map& updates) { + SharedRefPtr buffer = result->buffer(); + result->decode_first_row(); + ResultIterator rows(result); + + while (rows.next()) { + std::string keyspace_name; + const Row* row = rows.row(); + + if (!row->get_string_by_name("keyspace_name", &keyspace_name)) { + LOG_ERROR("Unable to column value for 'keyspace_name'"); + continue; + } + + KeyspaceMetadata* keyspace = get_or_create_keyspace(keyspace_name); + keyspace->update(version, buffer, row); + updates.insert(std::make_pair(keyspace_name, *keyspace)); + } +} + +void Metadata::InternalData::update_tables(int version, ResultResponse* tables_result, ResultResponse* columns_result) { + SharedRefPtr buffer = tables_result->buffer(); + + tables_result->decode_first_row(); + ResultIterator rows(tables_result); + + std::string keyspace_name; + std::string columnfamily_name; + KeyspaceMetadata* keyspace; + + while (rows.next()) { + std::string temp_keyspace_name; + const Row* row = rows.row(); + + if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || + !row->get_string_by_name("columnfamily_name", &columnfamily_name)) { + LOG_ERROR("Unable to column value for 'keyspace_name' or 'columnfamily_name'"); + continue; + } + if (keyspace_name != temp_keyspace_name) { + keyspace_name = temp_keyspace_name; + keyspace = get_or_create_keyspace(keyspace_name); + } + keyspace->add_table(TableMetadata::Ptr(new TableMetadata(columnfamily_name, version, buffer, row))); + } + + update_columns(version, columns_result); +} + +void Metadata::InternalData::update_types(ResultResponse* result) { + result->decode_first_row(); + ResultIterator rows(result); + + while (rows.next()) { + std::string keyspace_name; + std::string type_name; + const Row* row = rows.row(); + + if (!row->get_string_by_name("keyspace_name", &keyspace_name) || + !row->get_string_by_name("type_name", &type_name)) { + LOG_ERROR("Unable to column value for 'keyspace_name' or 'type_name'"); + continue; + } + + const Value* names_value = row->get_by_name("field_names"); + if (names_value == NULL || names_value->is_null()) { + LOG_ERROR("'field_name's column for keyspace \"%s\" and type \"%s\" is null", + keyspace_name.c_str(), type_name.c_str()); + continue; + } + + const Value* types_value = row->get_by_name("field_types"); + if (types_value == NULL || types_value->is_null()) { + LOG_ERROR("'field_type's column for keyspace '%s' and type '%s' is null", + keyspace_name.c_str(), type_name.c_str()); + continue; + } + + CollectionIterator names(names_value); + CollectionIterator types(types_value); + + UserType::FieldVec fields; + + while (names.next()) { + if(!types.next()) { + LOG_ERROR("The number of 'field_type's doesn\"t match the number of field_names for keyspace \"%s\" and type \"%s\"", + keyspace_name.c_str(), type_name.c_str()); + break; + } + + const cass::Value* name = names.value(); + const cass::Value* type = types.value(); + + if (name->is_null() || type->is_null()) { + LOG_ERROR("'field_name' or 'field_type' is null for keyspace \"%s\" and type \"%s\"", + keyspace_name.c_str(), type_name.c_str()); + break; + } + + std::string field_name(name->to_string()); + + SharedRefPtr data_type = TypeParser::parse_one(type->to_string()); + if (!data_type) { + LOG_ERROR("Invalid 'field_type' for field \"%s\", keyspace \"%s\" and type \"%s\"", + field_name.c_str(), + keyspace_name.c_str(), + type_name.c_str()); + break; + } + + fields.push_back(UserType::Field(field_name, data_type)); + } + + get_or_create_keyspace(keyspace_name)->add_type( + SharedRefPtr(new UserType(keyspace_name, type_name, fields))); + } +} + +void Metadata::InternalData::drop_keyspace(const std::string& keyspace_name) { + keyspaces_->erase(keyspace_name); +} + +void Metadata::InternalData::drop_table(const std::string& keyspace_name, const std::string& table_name) { + KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); + if (i == keyspaces_->end()) return; + i->second.drop_table(table_name); +} + +void Metadata::InternalData::drop_type(const std::string& keyspace_name, const std::string& type_name) { + KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); + if (i == keyspaces_->end()) return; + i->second.drop_type(type_name); +} + +void Metadata::InternalData::update_columns(int version, ResultResponse* result) { + SharedRefPtr buffer = result->buffer(); + + result->decode_first_row(); + ResultIterator rows(result); + + std::string keyspace_name; + std::string columnfamily_name; + std::string column_name; + TableMetadata::Ptr table; + while (rows.next()) { + std::string temp_keyspace_name; + std::string temp_columnfamily_name; + const Row* row = rows.row(); + + if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || + !row->get_string_by_name("columnfamily_name", &temp_columnfamily_name) || + !row->get_string_by_name("column_name", &column_name)) { + LOG_ERROR("Unable to column value for 'keyspace_name', 'columnfamily_name' or 'column_name'"); + continue; } + + if (keyspace_name != temp_keyspace_name || + columnfamily_name != temp_columnfamily_name) { + if (table) table->build_keys(); + + keyspace_name = temp_keyspace_name; + columnfamily_name = temp_columnfamily_name; + + table = get_or_create_keyspace(keyspace_name)->get_or_create_table(columnfamily_name); + table->clear_columns(); + } + + table->add_column(ColumnMetadata::Ptr(new ColumnMetadata(column_name, version, buffer, row))); + } +} + +KeyspaceMetadata* Metadata::InternalData::get_or_create_keyspace(const std::string& name) { + KeyspaceMetadata::Map::iterator i = keyspaces_->find(name); + if (i == keyspaces_->end()) { + i = keyspaces_->insert(std::make_pair(name, KeyspaceMetadata(name))).first; } + return &i->second; } } // namespace cass diff --git a/src/metadata.hpp b/src/metadata.hpp index 21c6f9647..05ef91844 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -19,6 +19,7 @@ #include "copy_on_write_ptr.hpp" #include "iterator.hpp" +#include "macros.hpp" #include "ref_counted.hpp" #include "scoped_lock.hpp" #include "scoped_ptr.hpp" @@ -36,11 +37,12 @@ class Row; class ResultResponse; template -class SchemaMapIteratorImpl { +class MapIteratorImpl { public: - typedef std::map Map; + typedef T ItemType; + typedef std::map Collection; - SchemaMapIteratorImpl(const Map& map) + MapIteratorImpl(const Collection& map) : next_(map.begin()) , end_(map.end()) {} @@ -52,26 +54,54 @@ class SchemaMapIteratorImpl { return true; } - const T* item() const { - return ¤t_->second; + const T& item() const { + return current_->second; } private: - typename Map::const_iterator next_; - typename Map::const_iterator current_; - typename Map::const_iterator end_; + typename Collection::const_iterator next_; + typename Collection::const_iterator current_; + typename Collection::const_iterator end_; }; -class SchemaMetadataField { +template +class VecIteratorImpl { +public: + typedef T ItemType; + typedef std::vector Collection; + + VecIteratorImpl(const Collection& vec) + : next_(vec.begin()) + , end_(vec.end()) {} + + bool next() { + if (next_ == end_) { + return false; + } + current_ = next_++; + return true; + } + + const T& item() const { + return (*current_); + } + +private: + typename Collection::const_iterator next_; + typename Collection::const_iterator current_; + typename Collection::const_iterator end_; +}; + +class MetadataField { public: - typedef std::map Map; + typedef std::map Map; - SchemaMetadataField() {} + MetadataField() {} - SchemaMetadataField(const std::string& name) + MetadataField(const std::string& name) : name_(name) {} - SchemaMetadataField(const std::string& name, + MetadataField(const std::string& name, const Value& value, const SharedRefPtr& buffer) : name_(name) @@ -92,193 +122,215 @@ class SchemaMetadataField { SharedRefPtr buffer_; }; -class SchemaMetadataFieldIterator : public Iterator { +class MetadataFieldIterator : public Iterator { public: - typedef SchemaMapIteratorImpl Map; + typedef MapIteratorImpl::Collection Map; - SchemaMetadataFieldIterator(const Map& map) - : Iterator(CASS_ITERATOR_TYPE_SCHEMA_META_FIELD) + MetadataFieldIterator(const Map& map) + : Iterator(CASS_ITERATOR_TYPE_META_FIELD) , impl_(map) {} virtual bool next() { return impl_.next(); } - const SchemaMetadataField* field() const { return impl_.item(); } + const MetadataField* field() const { return &impl_.item(); } private: - SchemaMapIteratorImpl impl_; + MapIteratorImpl impl_; }; -class SchemaMetadata { +class MetadataBase { public: - SchemaMetadata(CassSchemaMetaType type) - : type_(type) {} + MetadataBase(const std::string& name) + : name_(name) { } - virtual ~SchemaMetadata() {} + const std::string name() const { return name_; } - CassSchemaMetaType type() const { return type_; } - - virtual const SchemaMetadata* get_entry(const std::string& name) const = 0; - virtual Iterator* iterator() const = 0; - - const SchemaMetadataField* get_field(const std::string& name) const; + const MetadataField* get_field(const std::string& name) const; std::string get_string_field(const std::string& name) const; - Iterator* iterator_fields() const { return new SchemaMetadataFieldIterator(fields_); } + Iterator* iterator_fields() const { return new MetadataFieldIterator(fields_); } protected: - void add_field(const SharedRefPtr& buffer, const Row* row, const std::string& name); + const Value* add_field(const SharedRefPtr& buffer, const Row* row, const std::string& name); void add_json_list_field(int version, const Row* row, const std::string& name); void add_json_map_field(int version, const Row* row, const std::string& name); - SchemaMetadataField::Map fields_; + MetadataField::Map fields_; private: - const CassSchemaMetaType type_; + const std::string name_; }; -class SchemaMetadataIterator : public Iterator { +template +class MetadataIteratorImpl : public Iterator { public: - SchemaMetadataIterator() - : Iterator(CASS_ITERATOR_TYPE_SCHEMA_META) {} - virtual const SchemaMetadata* meta() const = 0; -}; + typedef typename IteratorImpl::Collection Collection; -template -class SchemaMetadataIteratorImpl : public SchemaMetadataIterator { -public: - typedef typename SchemaMapIteratorImpl::Map Map; - - SchemaMetadataIteratorImpl(const Map& map) - : impl_(map) {} + MetadataIteratorImpl(CassIteratorType type, const Collection& colleciton) + : Iterator(type) + , impl_(colleciton) {} virtual bool next() { return impl_.next(); } - virtual const SchemaMetadata* meta() const { return impl_.item(); } -private: - SchemaMapIteratorImpl impl_; +protected: + IteratorImpl impl_; }; -class ColumnMetadata : public SchemaMetadata { +class ColumnMetadata : public MetadataBase, public RefCounted { public: - typedef std::map Map; + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector Vec; - ColumnMetadata() - : SchemaMetadata(CASS_SCHEMA_META_TYPE_COLUMN) {} + ColumnMetadata(const std::string& name) + : MetadataBase(name) + , type_(CASS_COLUMN_TYPE_REGULAR) + , position_(0) + , is_reversed_(false) { } - virtual const SchemaMetadata* get_entry(const std::string& name) const { - return NULL; - } - virtual Iterator* iterator() const { return NULL; } + ColumnMetadata(const std::string& name, + int version, const SharedRefPtr& buffer, const Row* row); - void update(int version, const SharedRefPtr& buffer, const Row* row); + CassColumnType type() const { return type_; } + int32_t position() const { return position_; } + const SharedRefPtr& data_type() const { return data_type_; } + bool is_reversed() const { return is_reversed_; } + +private: + CassColumnType type_; + int32_t position_; + SharedRefPtr data_type_; + bool is_reversed_; + +private: + DISALLOW_COPY_AND_ASSIGN(ColumnMetadata); }; -class TableMetadata : public SchemaMetadata { +class TableMetadata : public MetadataBase, public RefCounted { public: - typedef std::map Map; - typedef SchemaMetadataIteratorImpl ColumnIterator; + typedef SharedRefPtr Ptr; + typedef std::map Map; typedef std::vector KeyAliases; - TableMetadata() - : SchemaMetadata(CASS_SCHEMA_META_TYPE_TABLE) {} + class ColumnIterator : public MetadataIteratorImpl > { + public: + ColumnIterator(const ColumnIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_COLUMN_META, collection) { } + const ColumnMetadata* column() const { return impl_.item().get(); } + }; - virtual const SchemaMetadata* get_entry(const std::string& name) const; - virtual Iterator* iterator() const { return new ColumnIterator(columns_); } + TableMetadata(const std::string& name) + : MetadataBase(name) { } - ColumnMetadata* get_or_create(const std::string& name) { return &columns_[name]; } - void update(int version, const SharedRefPtr& buffer, const Row* row); + TableMetadata(const std::string& name, + int version, const SharedRefPtr& buffer, const Row* row); + CassUuid id() const { return id_; } + const ColumnMetadata::Vec& columns() const { return columns_; } + const ColumnMetadata::Vec& partition_key() const { return partition_key_; } + const ColumnMetadata::Vec& clustering_key() const { return clustering_key_; } + + Iterator* iterator_columns() const { return new ColumnIterator(columns_); } + const ColumnMetadata* get_column(const std::string& name) const; + const ColumnMetadata::Ptr& get_or_create_column(const std::string& name); + void add_column(const ColumnMetadata::Ptr& column); + void clear_columns(); + void build_keys(); void key_aliases(KeyAliases* output) const; - void clear_columns() { columns_.clear(); } private: - ColumnMetadata::Map columns_; + CassUuid id_; + ColumnMetadata::Vec columns_; + ColumnMetadata::Map columns_by_name_; + ColumnMetadata::Vec partition_key_; + ColumnMetadata::Vec clustering_key_; + +private: + DISALLOW_COPY_AND_ASSIGN(TableMetadata); }; -class KeyspaceMetadata : public SchemaMetadata, public RefCounted { +class KeyspaceMetadata : public MetadataBase { public: - typedef SharedRefPtr Ptr; - typedef std::map Map; - typedef CopyOnWritePtr MapPtr; - typedef SchemaMetadataIteratorImpl TableIterator; - typedef std::map > UserTypeMap; - - KeyspaceMetadata() - : SchemaMetadata(CASS_SCHEMA_META_TYPE_KEYSPACE) {} + typedef std::map Map; + typedef CopyOnWritePtr MapPtr; + typedef std::map > TypeMap; - virtual const SchemaMetadata* get_entry(const std::string& name) const; - virtual Iterator* iterator() const { return new TableIterator(tables_); } + class TableIterator : public MetadataIteratorImpl > { + public: + TableIterator(const TableIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_TABLE_META, collection) { } + const TableMetadata* table() const { return impl_.item().get(); } + }; - TableMetadata* get_or_create_table(const std::string& name) { return &tables_[name]; } + class TypeIterator : public MetadataIteratorImpl > > { + public: + TypeIterator(const TypeIterator::Collection& collection) + : MetadataIteratorImpl > >(CASS_ITERATOR_TYPE_TYPE_META, collection) { } + const UserType* type() const { return impl_.item().get(); } + }; - SharedRefPtr get_type(const std::string& type_name) const; + KeyspaceMetadata(const std::string& name) + : MetadataBase(name) + , tables_(new TableMetadata::Map) + , types_(new TypeMap) { } void update(int version, const SharedRefPtr& buffer, const Row* row); - void add_type(const SharedRefPtr& user_type); + Iterator* iterator_tables() const { return new TableIterator(*tables_); } + const TableMetadata* get_table(const std::string& table_name) const; + const TableMetadata::Ptr& get_or_create_table(const std::string& name); + void add_table(const TableMetadata::Ptr& table); void drop_table(const std::string& table_name); + + Iterator* iterator_types() const { return new TypeIterator(*types_); } + const UserType* get_type(const std::string& type_name) const; + void add_type(const SharedRefPtr& user_type); void drop_type(const std::string& type_name); std::string strategy_class() const { return get_string_field("strategy_class"); } - const SchemaMetadataField* strategy_options() const { return get_field("strategy_options"); } + const MetadataField* strategy_options() const { return get_field("strategy_options"); } private: - TableMetadata::Map tables_; - UserTypeMap types_; + CopyOnWritePtr tables_; + CopyOnWritePtr types_; }; class Metadata { public: - class KeyspaceIterator : public SchemaMetadataIterator { + class KeyspaceIterator : public MetadataIteratorImpl > { public: - typedef typename SchemaMapIteratorImpl::Map Map; - - KeyspaceIterator(const Map& map) - : impl_(map) {} - - virtual bool next() { return impl_.next(); } - virtual const SchemaMetadata* meta() const { return impl_.item()->get(); } - - private: - SchemaMapIteratorImpl impl_; + KeyspaceIterator(const KeyspaceIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_KEYSPACE_META, collection) { } + const KeyspaceMetadata* keyspace() const { return &impl_.item(); } }; - typedef std::map KeyspacePointerMap; - class Snapshot { + class SchemaSnapshot { public: - Snapshot() - : keyspaces_(new KeyspaceMetadata::Map()) { } + SchemaSnapshot(uint32_t version, const KeyspaceMetadata::MapPtr& keyspaces) + : version_(version) + , keyspaces_(keyspaces) { } - const SchemaMetadata* get_keyspace(const std::string& name) const; + uint32_t version() const { return version_; } - SharedRefPtr get_type(const std::string& keyspace_name, - const std::string& type_name) const; + const KeyspaceMetadata* get_keyspace(const std::string& name) const; + Iterator* iterator_keyspaces() const { return new KeyspaceIterator(*keyspaces_); } - Iterator* iterator() const { return new KeyspaceIterator(*keyspaces_); } + const UserType* get_type(const std::string& keyspace_name, + const std::string& type_name) const; void get_table_key_columns(const std::string& ks_name, const std::string& cf_name, std::vector* output) const; - private: - // We don't want external snapshots to be modified - friend class Metadata; - - const KeyspaceMetadata::Ptr& get_or_create_keyspace(const std::string& keyspace_name) { - KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); - if (i == keyspaces_->end()) { - i = keyspaces_->insert(std::make_pair(keyspace_name, - KeyspaceMetadata::Ptr(new KeyspaceMetadata()))).first; - } - return i->second; - } - private: + uint32_t version_; KeyspaceMetadata::MapPtr keyspaces_; }; - +public: Metadata() - : protocol_version_(0) { + : updating_(&front_) + , schema_snapshot_version_(0) + , protocol_version_(0) { uv_mutex_init(&mutex_); } @@ -286,11 +338,7 @@ class Metadata { uv_mutex_destroy(&mutex_); } - Snapshot* snapshot() const; - - void set_protocol_version(int version) { - protocol_version_ = version; - } + SchemaSnapshot schema_snapshot() const; void update_keyspaces(ResultResponse* result); void update_tables(ResultResponse* tables_result, ResultResponse* columns_result); @@ -300,8 +348,18 @@ class Metadata { void drop_table(const std::string& keyspace_name, const std::string& table_name); void drop_type(const std::string& keyspace_name, const std::string& type_name); + // This clears and allows updates to the back buffer while preserving + // the front buffer for snapshots. + void clear_and_update_back(); + + // This swaps the back buffer to the front and makes incremental updates + // happen directly to the front buffer. + void swap_to_back_and_update_front(); + void clear(); + void set_protocol_version(int version) { protocol_version_ = version; } + void set_partitioner(const std::string& partitioner_class) { token_map_.set_partitioner(partitioner_class); } void update_host(SharedRefPtr& host, const TokenStringList& tokens) { token_map_.update_host(host, tokens); } void build() { token_map_.build(); } @@ -310,20 +368,68 @@ class Metadata { const TokenMap& token_map() const { return token_map_; } private: - void update_columns(ResultResponse* result); + bool is_front_buffer() const { return updating_ == &front_; } private: + class InternalData { + public: + InternalData() + : keyspaces_(new KeyspaceMetadata::Map()) { } + + const KeyspaceMetadata::MapPtr& keyspaces() const { return keyspaces_; } + + void update_keyspaces(int version, ResultResponse* result, KeyspaceMetadata::Map& updates); + void update_tables(int version, ResultResponse* tables_result, ResultResponse* columns_result); + void update_types(ResultResponse* result); + + void drop_keyspace(const std::string& keyspace_name); + void drop_table(const std::string& keyspace_name, const std::string& table_name); + void drop_type(const std::string& keyspace_name, const std::string& type_name); + + void clear() { keyspaces_->clear(); } + + void swap(InternalData& other) { + CopyOnWritePtr temp = other.keyspaces_; + keyspaces_ = other.keyspaces_; + other.keyspaces_ = temp; + } + + private: + void update_columns(int version, ResultResponse* result); + + KeyspaceMetadata* get_or_create_keyspace(const std::string& name); + + private: + CopyOnWritePtr keyspaces_; + + private: + DISALLOW_COPY_AND_ASSIGN(InternalData); + }; + + InternalData* updating_; + InternalData front_; + InternalData back_; + + uint32_t schema_snapshot_version_; + // This lock prevents partial snapshots when updating metadata mutable uv_mutex_t mutex_; - Snapshot snapshot_; + // Only used internally on a single thread so it doesn't currently use + // copy-on-write. When this is exposed externally it needs to be + // moved into the InternalData class and made to use copy-on-write. TokenMap token_map_; // Only used internally on a single thread, there's // no need for copy-on-write. int protocol_version_; + +private: + DISALLOW_COPY_AND_ASSIGN(Metadata); }; } // namespace cass #endif + + diff --git a/src/replication_strategy.cpp b/src/replication_strategy.cpp index 31a5e00e2..7a9d54bcb 100644 --- a/src/replication_strategy.cpp +++ b/src/replication_strategy.cpp @@ -46,7 +46,7 @@ SharedRefPtr ReplicationStrategy::from_keyspace_meta(const const std::string NetworkTopologyStrategy::STRATEGY_CLASS("NetworkTopologyStrategy"); NetworkTopologyStrategy::NetworkTopologyStrategy(const std::string& strategy_class, - const SchemaMetadataField* strategy_options) + const MetadataField* strategy_options) : ReplicationStrategy(strategy_class) { build_dc_replicas(strategy_options, &replication_factors_); } @@ -135,7 +135,7 @@ void NetworkTopologyStrategy::tokens_to_replicas(const TokenHostMap& primary, To } } -void NetworkTopologyStrategy::build_dc_replicas(const SchemaMetadataField* strategy_options, +void NetworkTopologyStrategy::build_dc_replicas(const MetadataField* strategy_options, NetworkTopologyStrategy::DCReplicaCountMap* output) { if (strategy_options != NULL) { MapIterator itr(strategy_options->value()); @@ -156,7 +156,7 @@ void NetworkTopologyStrategy::build_dc_replicas(const SchemaMetadataField* strat const std::string SimpleStrategy::STRATEGY_CLASS("SimpleStrategy"); SimpleStrategy::SimpleStrategy(const std::string& strategy_class, - const SchemaMetadataField* strategy_options) + const MetadataField* strategy_options) : ReplicationStrategy(strategy_class) , replication_factor_(0) { replication_factor_ = get_replication_factor(strategy_options); @@ -187,7 +187,7 @@ void SimpleStrategy::tokens_to_replicas(const TokenHostMap& primary, TokenReplic } } -size_t SimpleStrategy::get_replication_factor(const SchemaMetadataField* strategy_options) { +size_t SimpleStrategy::get_replication_factor(const MetadataField* strategy_options) { if (strategy_options != NULL) { MapIterator itr(strategy_options->value()); while (itr.next()) { diff --git a/src/replication_strategy.hpp b/src/replication_strategy.hpp index 9790da3b5..08c641191 100644 --- a/src/replication_strategy.hpp +++ b/src/replication_strategy.hpp @@ -26,7 +26,7 @@ namespace cass { class KeyspaceMetadata; -class SchemaMetadataField; +class MetadataField; typedef std::vector Token; typedef std::map > TokenHostMap; @@ -55,7 +55,7 @@ class NetworkTopologyStrategy : public ReplicationStrategy { static const std::string STRATEGY_CLASS; NetworkTopologyStrategy(const std::string& strategy_class, - const SchemaMetadataField* strategy_options); + const MetadataField* strategy_options); virtual ~NetworkTopologyStrategy() {} virtual bool equal(const KeyspaceMetadata& ks_meta); @@ -68,7 +68,7 @@ class NetworkTopologyStrategy : public ReplicationStrategy { , replication_factors_(replication_factors) {} private: - static void build_dc_replicas(const SchemaMetadataField* strategy_options, DCReplicaCountMap* dc_replicas); + static void build_dc_replicas(const MetadataField* strategy_options, DCReplicaCountMap* dc_replicas); DCReplicaCountMap replication_factors_; }; @@ -78,7 +78,7 @@ class SimpleStrategy : public ReplicationStrategy { static const std::string STRATEGY_CLASS; SimpleStrategy(const std::string& strategy_class, - const SchemaMetadataField* strategy_options); + const MetadataField* strategy_options); virtual ~SimpleStrategy() {} virtual bool equal(const KeyspaceMetadata& ks_meta); @@ -91,7 +91,7 @@ class SimpleStrategy : public ReplicationStrategy { , replication_factor_(replication_factor) {} private: - static size_t get_replication_factor(const SchemaMetadataField* strategy_options); + static size_t get_replication_factor(const MetadataField* strategy_options); size_t replication_factor_; }; diff --git a/src/request_handler.hpp b/src/request_handler.hpp index 57e168855..9c706b701 100644 --- a/src/request_handler.hpp +++ b/src/request_handler.hpp @@ -43,7 +43,7 @@ class ResponseFuture : public Future { public: ResponseFuture(const Metadata& metadata) : Future(CASS_FUTURE_TYPE_RESPONSE) - , snapshot(metadata.snapshot()) { } + , schema_metadata(metadata.schema_snapshot()) { } void set_response(Address address, const SharedRefPtr& response) { ScopedMutex lock(&mutex_); @@ -79,7 +79,7 @@ class ResponseFuture : public Future { } std::string statement; - ScopedPtr snapshot; + Metadata::SchemaSnapshot schema_metadata; private: Address address_; diff --git a/src/session.cpp b/src/session.cpp index a372217d4..618128830 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -92,8 +92,8 @@ CassFuture* cass_session_execute_batch(CassSession* session, const CassBatch* ba return CassFuture::to(session->execute(batch->from())); } -const CassSchema* cass_session_get_schema(const CassSession* session) { - return CassSchema::to(session->metadata().snapshot()); +const CassSchemaMeta* cass_session_get_schema_meta(const CassSession* session) { + return CassSchemaMeta::to(new cass::Metadata::SchemaSnapshot(session->metadata().schema_snapshot())); } void cass_session_get_metrics(const CassSession* session, diff --git a/src/testing.cpp b/src/testing.cpp index f7e951b03..ca0f3a023 100644 --- a/src/testing.cpp +++ b/src/testing.cpp @@ -61,20 +61,10 @@ std::string get_contact_points_from_cluster(CassCluster* cluster) { return str; } -CassSchemaMeta* get_schema_meta_from_keyspace(const CassSchema* schema, const std::string& keyspace) { - CassSchemaMeta* foundSchemaMeta = NULL; - - if (schema) { - foundSchemaMeta = reinterpret_cast(const_cast(schema->from()->get_keyspace(keyspace))); - } - - return foundSchemaMeta; -} - -std::vector get_user_data_type_field_names(const CassSchema* schema, const std::string& keyspace, const std::string& udt_name) { +std::vector get_user_data_type_field_names(const CassSchemaMeta* schema_meta, const std::string& keyspace, const std::string& udt_name) { std::vector udt_field_names; - if (schema) { - SharedRefPtr udt = schema->from()->get_type(keyspace, udt_name); + if (schema_meta) { + const cass::UserType* udt = schema_meta->get_type(keyspace, udt_name); if (udt) { for (cass::UserType::FieldVec::const_iterator it = udt->fields().begin(); it != udt->fields().end(); ++it) { udt_field_names.push_back((*it).name); diff --git a/src/testing.hpp b/src/testing.hpp index a80e6a006..533fdda82 100644 --- a/src/testing.hpp +++ b/src/testing.hpp @@ -33,9 +33,7 @@ CASS_EXPORT int get_port_from_cluster(CassCluster* cluster); CASS_EXPORT std::string get_contact_points_from_cluster(CassCluster* cluster); -CASS_EXPORT CassSchemaMeta* get_schema_meta_from_keyspace(const CassSchema* session, const std::string& keyspace); - -CASS_EXPORT std::vector get_user_data_type_field_names(const CassSchema* schema, const std::string& keyspace, const std::string& udt_name); +CASS_EXPORT std::vector get_user_data_type_field_names(const CassSchemaMeta* schema_meta, const std::string& keyspace, const std::string& udt_name); CASS_EXPORT int64_t create_murmur3_hash_from_string(const std::string &value); diff --git a/src/value.cpp b/src/value.cpp index ba4ac1170..e0c6f7a89 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -208,4 +208,19 @@ Value::Value(int protocol_version, } } +int32_t Value::as_int32() const { + assert(value_type() == CASS_VALUE_TYPE_INT); + int32_t value; + decode_int32(data_, value); + return value; +} + +CassUuid Value::as_uuid() const { + assert(value_type() == CASS_VALUE_TYPE_UUID || value_type() == CASS_VALUE_TYPE_TIMEUUID); + CassUuid value; + decode_uuid(data_, &value); + return value; + +} + } // namespace cassandra diff --git a/src/value.hpp b/src/value.hpp index 87cbfc140..4f67b7b33 100644 --- a/src/value.hpp +++ b/src/value.hpp @@ -134,6 +134,9 @@ class Value { return to_string_ref().to_string(); } + int32_t as_int32() const; + CassUuid as_uuid() const; + private: int protocol_version_; SharedRefPtr data_type_; diff --git a/test/integration_tests/src/test_schema_metadata.cpp b/test/integration_tests/src/test_schema_metadata.cpp index f39d6a12d..fd7e1ebe2 100644 --- a/test/integration_tests/src/test_schema_metadata.cpp +++ b/test/integration_tests/src/test_schema_metadata.cpp @@ -21,6 +21,7 @@ #include "cassandra.h" #include "testing.hpp" #include "test_utils.hpp" +#include "metadata.hpp" #include #include @@ -50,15 +51,15 @@ * schema metadata validation against. */ struct TestSchemaMetadata : public test_utils::SingleSessionTest { - const CassSchema* schema_; + const CassSchemaMeta* schema_meta_; TestSchemaMetadata() : SingleSessionTest(1, 0) - , schema_(NULL) {} + , schema_meta_(NULL) {} ~TestSchemaMetadata() { - if (schema_) { - cass_schema_free(schema_); + if (schema_meta_) { + cass_schema_meta_free(schema_meta_); } } @@ -78,25 +79,25 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { } void refresh_schema_meta() { - if (schema_) { - const CassSchema* old(schema_); - schema_ = cass_session_get_schema(session); + if (schema_meta_) { + const CassSchemaMeta* old = schema_meta_; + schema_meta_ = cass_session_get_schema_meta(session); for (size_t i = 0; - i < 10 && cass::get_schema_meta_from_keyspace(schema_, "system") == cass::get_schema_meta_from_keyspace(old, "system"); + i < 10 && cass_schema_meta_version(schema_meta_) == cass_schema_meta_version(old); ++i) { boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); - cass_schema_free(schema_); - schema_ = cass_session_get_schema(session); + cass_schema_meta_free(schema_meta_); + schema_meta_ = cass_session_get_schema_meta(session); } - if (cass::get_schema_meta_from_keyspace(schema_, "system") == cass::get_schema_meta_from_keyspace(old, "system")) { + if (cass_schema_meta_version(schema_meta_) == cass_schema_meta_version(old)) { boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_messages); BOOST_TEST_MESSAGE("Schema metadata was not refreshed or was not changed"); boost::unit_test::unit_test_log_t::instance().set_threshold_level(boost::unit_test::log_all_errors); } - cass_schema_free(old); + cass_schema_meta_free(old); } else { - schema_ = cass_session_get_schema(session); + schema_meta_ = cass_session_get_schema_meta(session); } } @@ -116,44 +117,39 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { refresh_schema_meta(); } - const CassSchemaMeta* schema_get_keyspace(const std::string& ks_name) { - const CassSchemaMeta* ks_meta = cass_schema_get_keyspace(schema_, ks_name.c_str()); + const CassKeyspaceMeta* schema_get_keyspace(const std::string& ks_name) { + const CassKeyspaceMeta* ks_meta = cass_schema_meta_keyspace_by_name(schema_meta_, ks_name.c_str()); BOOST_REQUIRE(ks_meta); return ks_meta; } - const CassSchemaMeta* schema_get_table(const std::string& ks_name, + const CassTableMeta* schema_get_table(const std::string& ks_name, const std::string& table_name) { - const CassSchemaMeta* table_meta = cass_schema_meta_get_entry(schema_get_keyspace(ks_name), table_name.c_str()); + const CassTableMeta* table_meta = cass_keyspace_meta_table_by_name(schema_get_keyspace(ks_name), table_name.c_str()); BOOST_REQUIRE(table_meta); return table_meta; } - const CassSchemaMeta* schema_get_column(const std::string& ks_name, + const CassColumnMeta* schema_get_column(const std::string& ks_name, const std::string& table_name, const std::string& col_name) { - const CassSchemaMeta* col_meta = cass_schema_meta_get_entry(schema_get_table(ks_name, table_name), col_name.c_str()); + const CassColumnMeta* col_meta = cass_table_meta_column_by_name(schema_get_table(ks_name, table_name), col_name.c_str()); BOOST_REQUIRE(col_meta); return col_meta; } - void verify_fields(const CassSchemaMeta* meta, const std::set& expected_fields) { + void verify_fields(const test_utils::CassIteratorPtr& itr, const std::set& expected_fields) { // all fields present, nothing extra std::set observed; - test_utils::CassIteratorPtr itr(cass_iterator_fields_from_schema_meta(meta)); while (cass_iterator_next(itr.get())) { - const CassSchemaMetaField* field = cass_iterator_get_schema_meta_field(itr.get()); + const CassMetaField* field = cass_iterator_get_meta_field(itr.get()); CassString name; - cass_schema_meta_field_name(field, &name.data, &name.length); + cass_meta_field_name(field, &name.data, &name.length); observed.insert(std::string(name.data, name.length)); - // can get same field by name as by iterator - BOOST_CHECK_EQUAL(cass_schema_meta_get_field(meta, std::string(name.data, name.length).c_str()), field); } BOOST_REQUIRE_EQUAL_COLLECTIONS(observed.begin(), observed.end(), expected_fields.begin(), expected_fields.end()); - - BOOST_CHECK(!cass_schema_meta_get_field(meta, "some bogus field")); } @@ -209,15 +205,32 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { return fields; } - void verify_columns(const CassSchemaMeta* table_meta) { - test_utils::CassIteratorPtr itr(cass_iterator_from_schema_meta(table_meta)); + void verify_fields_by_name(const CassKeyspaceMeta* keyspace_meta, const std::set& fields) { + for (std::set::iterator i = fields.begin(); i != fields.end(); ++i) { + BOOST_CHECK(cass_keyspace_meta_field_by_name(keyspace_meta, i->c_str()) != NULL); + } + } + + void verify_fields_by_name(const CassTableMeta* table_meta, const std::set& fields) { + for (std::set::iterator i = fields.begin(); i != fields.end(); ++i) { + BOOST_CHECK(cass_table_meta_field_by_name(table_meta, i->c_str()) != NULL); + } + } + + void verify_fields_by_name(const CassColumnMeta* column_meta, const std::set& fields) { + for (std::set::iterator i = fields.begin(); i != fields.end(); ++i) { + BOOST_CHECK(cass_column_meta_field_by_name(column_meta, i->c_str()) != NULL); + } + } + + void verify_columns(const CassTableMeta* table_meta) { + test_utils::CassIteratorPtr itr(cass_iterator_columns_from_table_meta(table_meta)); while (cass_iterator_next(itr.get())) { - const CassSchemaMeta* col_meta = cass_iterator_get_schema_meta(itr.get()); - BOOST_REQUIRE_EQUAL(cass_schema_meta_type(col_meta), CASS_SCHEMA_META_TYPE_COLUMN); - verify_fields(col_meta, column_fields()); + const CassColumnMeta* col_meta = cass_iterator_get_column_meta(itr.get()); + verify_fields(test_utils::CassIteratorPtr(cass_iterator_fields_from_column_meta(col_meta)), column_fields()); + verify_fields_by_name(col_meta, column_fields()); // no entries at this level - BOOST_CHECK(!cass_iterator_from_schema_meta(col_meta)); - BOOST_CHECK(!cass_schema_meta_get_entry(col_meta, "some bogus entry")); + BOOST_CHECK(!cass_column_meta_field_by_name(col_meta, "some bogus entry")); } } @@ -281,16 +294,17 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { void verify_table(const std::string& ks_name, const std::string& table_name, const std::string& comment, const std::string& non_key_column) { - const CassSchemaMeta* table_meta = schema_get_table(SIMPLE_STRATEGY_KEYSPACE_NAME, ALL_DATA_TYPES_TABLE_NAME); + const CassTableMeta* table_meta = schema_get_table(SIMPLE_STRATEGY_KEYSPACE_NAME, ALL_DATA_TYPES_TABLE_NAME); - verify_fields(table_meta, table_fields()); - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "keyspace_name")), SIMPLE_STRATEGY_KEYSPACE_NAME); - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "columnfamily_name")), ALL_DATA_TYPES_TABLE_NAME); + verify_fields(test_utils::CassIteratorPtr(cass_iterator_fields_from_table_meta(table_meta)), table_fields()); + verify_fields_by_name(table_meta, table_fields()); + verify_value(cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "keyspace_name")), SIMPLE_STRATEGY_KEYSPACE_NAME); + verify_value(cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "columnfamily_name")), ALL_DATA_TYPES_TABLE_NAME); // not going for every field, just making sure one of each type (fixed, list, map) is correctly added - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "comment")), COMMENT); + verify_value(cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "comment")), COMMENT); - const CassValue* value = cass_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "compression_parameters")); + const CassValue* value = cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "compression_parameters")); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_MAP); BOOST_REQUIRE_GE(cass_value_item_count(value), 1ul); test_utils::CassIteratorPtr itr(cass_iterator_from_map(value)); @@ -309,40 +323,40 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { BOOST_CHECK(param_found); if ((version.major >= 2 && version.minor >= 2) || version.major >= 3) { - value = cass_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "cf_id")); + value = cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "cf_id")); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_UUID); } else { - value = cass_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "key_aliases")); + value = cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "key_aliases")); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_LIST); BOOST_CHECK_GE(cass_value_item_count(value), 1ul); } - BOOST_CHECK(!cass_schema_meta_get_entry(table_meta, "some bogus entry")); + BOOST_CHECK(!cass_table_meta_column_by_name(table_meta, "some bogus entry")); verify_columns(table_meta); // known column - BOOST_REQUIRE(cass_schema_meta_get_entry(table_meta, non_key_column.c_str())); + BOOST_REQUIRE(cass_table_meta_column_by_name(table_meta, non_key_column.c_str())); // goes away if (version.major >= 2) {// dropping a column not supported in 1.2 test_utils::execute_query(session, "ALTER TABLE "+table_name+" DROP "+non_key_column); refresh_schema_meta(); table_meta = schema_get_table(SIMPLE_STRATEGY_KEYSPACE_NAME, ALL_DATA_TYPES_TABLE_NAME); - BOOST_CHECK(!cass_schema_meta_get_entry(table_meta, non_key_column.c_str())); + BOOST_CHECK(!cass_table_meta_column_by_name(table_meta, non_key_column.c_str())); } // new column test_utils::execute_query(session, "ALTER TABLE "+table_name+" ADD jkldsfafdjsklafajklsljkfds text"); refresh_schema_meta(); table_meta = schema_get_table(SIMPLE_STRATEGY_KEYSPACE_NAME, ALL_DATA_TYPES_TABLE_NAME); - BOOST_CHECK(cass_schema_meta_get_entry(table_meta, "jkldsfafdjsklafajklsljkfds")); + BOOST_CHECK(cass_table_meta_column_by_name(table_meta, "jkldsfafdjsklafajklsljkfds")); // drop table test_utils::execute_query(session, "DROP TABLE "+table_name); refresh_schema_meta(); - const CassSchemaMeta* ks_meta = cass_schema_get_keyspace(schema_, SIMPLE_STRATEGY_KEYSPACE_NAME); - table_meta = cass_schema_meta_get_entry(ks_meta, ALL_DATA_TYPES_TABLE_NAME); + const CassKeyspaceMeta* ks_meta = cass_schema_meta_keyspace_by_name(schema_meta_, SIMPLE_STRATEGY_KEYSPACE_NAME); + table_meta = cass_keyspace_meta_table_by_name(ks_meta, ALL_DATA_TYPES_TABLE_NAME); BOOST_CHECK(!table_meta); } @@ -361,14 +375,14 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { bool durable_writes, const std::string& strategy_class, const std::map& strategy_options) { - const CassSchemaMeta* ks_meta = schema_get_keyspace(name); - BOOST_REQUIRE_EQUAL(cass_schema_meta_type(ks_meta), CASS_SCHEMA_META_TYPE_KEYSPACE); - verify_fields(ks_meta, keyspace_fields()); - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(ks_meta, "keyspace_name")), name); - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(ks_meta, "durable_writes")), (cass_bool_t)durable_writes); - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(ks_meta, "strategy_class")), strategy_class); - verify_value(cass_schema_meta_field_value(cass_schema_meta_get_field(ks_meta, "strategy_options")), strategy_options); - BOOST_CHECK(!cass_schema_meta_get_entry(ks_meta, "some bogus entry")); + const CassKeyspaceMeta* ks_meta = schema_get_keyspace(name); + verify_fields(test_utils::CassIteratorPtr(cass_iterator_fields_from_keyspace_meta(ks_meta)), keyspace_fields()); + verify_fields_by_name(ks_meta, keyspace_fields()); + verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "keyspace_name")), name); + verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "durable_writes")), (cass_bool_t)durable_writes); + verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "strategy_class")), strategy_class); + verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "strategy_options")), strategy_options); + BOOST_CHECK(!cass_keyspace_meta_table_by_name(ks_meta, "some bogus entry")); } @@ -382,7 +396,7 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { strategy_options.insert(std::make_pair("replication_factor", "2")); verify_keyspace("system_traces", true, SIMPLE_STRATEGY_CLASS_NAME, strategy_options); - test_utils::CassIteratorPtr itr(cass_iterator_from_schema(schema_)); + test_utils::CassIteratorPtr itr(cass_iterator_keyspaces_from_schema_meta(schema_meta_)); size_t keyspace_count = 0; while (cass_iterator_next(itr.get())) ++keyspace_count; size_t number_of_default_keyspaces = 2; @@ -413,7 +427,7 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { // keyspace goes away test_utils::execute_query(session, "DROP KEYSPACE " SIMPLE_STRATEGY_KEYSPACE_NAME); refresh_schema_meta(); - BOOST_CHECK(!cass_schema_get_keyspace(schema_, SIMPLE_STRATEGY_KEYSPACE_NAME)); + BOOST_CHECK(!cass_schema_meta_keyspace_by_name(schema_meta_, SIMPLE_STRATEGY_KEYSPACE_NAME)); // nts create_network_topology_strategy_keyspace(3, 2, true); @@ -438,7 +452,7 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { void verify_user_type(const std::string& ks_name, const std::string& udt_name, const std::vector& udt_datatypes) { - std::vector udt_field_names = cass::get_user_data_type_field_names(schema_, ks_name, udt_name); + std::vector udt_field_names = cass::get_user_data_type_field_names(schema_meta_, ks_name, udt_name); BOOST_REQUIRE_EQUAL_COLLECTIONS(udt_datatypes.begin(), udt_datatypes.end(), udt_field_names.begin(), udt_field_names.end()); } @@ -495,8 +509,8 @@ BOOST_AUTO_TEST_CASE(simple) { BOOST_AUTO_TEST_CASE(disable) { // Verify known keyspace { - test_utils::CassSchemaPtr schema(cass_session_get_schema(session)); - BOOST_CHECK(cass_schema_get_keyspace(schema.get(), "system") != NULL); + test_utils::CassSchemaMetaPtr schema_meta(cass_session_get_schema_meta(session)); + BOOST_CHECK(cass_schema_meta_keyspace_by_name(schema_meta.get(), "system") != NULL); } // Verify schema change event @@ -504,8 +518,8 @@ BOOST_AUTO_TEST_CASE(disable) { test_utils::execute_query(session, "CREATE KEYSPACE ks1 WITH replication = " "{ 'class' : 'SimpleStrategy', 'replication_factor' : 3 }"); verify_keyspace_created("ks1"); - test_utils::CassSchemaPtr schema(cass_session_get_schema(session)); - BOOST_CHECK(cass_schema_get_keyspace(schema.get(), "ks1") != NULL); + test_utils::CassSchemaMetaPtr schema_meta(cass_session_get_schema_meta(session)); + BOOST_CHECK(cass_schema_meta_keyspace_by_name(schema_meta.get(), "ks1") != NULL); } close_session(); @@ -517,8 +531,8 @@ BOOST_AUTO_TEST_CASE(disable) { // Verify known keyspace doesn't exist in metadata { - test_utils::CassSchemaPtr schema(cass_session_get_schema(session)); - BOOST_CHECK(cass_schema_get_keyspace(schema.get(), "system") == NULL); + test_utils::CassSchemaMetaPtr schema_meta(cass_session_get_schema_meta(session)); + BOOST_CHECK(cass_schema_meta_keyspace_by_name(schema_meta.get(), "system") == NULL); } // Verify schema change event didn't happen @@ -526,8 +540,8 @@ BOOST_AUTO_TEST_CASE(disable) { test_utils::execute_query(session, "CREATE KEYSPACE ks2 WITH replication = " "{ 'class' : 'SimpleStrategy', 'replication_factor' : 3 }"); verify_keyspace_created("ks2"); - test_utils::CassSchemaPtr schema(cass_session_get_schema(session)); - BOOST_CHECK(cass_schema_get_keyspace(schema.get(), "ks2") == NULL); + test_utils::CassSchemaMetaPtr schema_meta(cass_session_get_schema_meta(session)); + BOOST_CHECK(cass_schema_meta_keyspace_by_name(schema_meta.get(), "ks2") == NULL); } } diff --git a/test/integration_tests/src/test_udts.cpp b/test/integration_tests/src/test_udts.cpp index 7acec3445..e1b7fccc2 100644 --- a/test/integration_tests/src/test_udts.cpp +++ b/test/integration_tests/src/test_udts.cpp @@ -40,13 +40,13 @@ struct UDTTests : public test_utils::SingleSessionTest { /** * Session schema metadata */ - test_utils::CassSchemaPtr schema_; + test_utils::CassSchemaMetaPtr schema_meta_; /** * Update the session schema metadata */ void update_schema() { - schema_ = test_utils::CassSchemaPtr(cass_session_get_schema(session)); + schema_meta_ = test_utils::CassSchemaMetaPtr(cass_session_get_schema_meta(session)); } /** @@ -57,18 +57,21 @@ struct UDTTests : public test_utils::SingleSessionTest { void verify_user_type(const std::string& udt_name) { std::vector udt_field_names; unsigned int count = 0; + const CassDataType* datatype = NULL; while (udt_field_names.empty() && ++count <= 10) { update_schema(); - udt_field_names = cass::get_user_data_type_field_names(schema_.get(), test_utils::SIMPLE_KEYSPACE.c_str(), udt_name); - if (udt_field_names.empty()) { + const CassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta_.get(), test_utils::SIMPLE_KEYSPACE.c_str()); + BOOST_REQUIRE(keyspace_meta != NULL); + datatype = cass_keyspace_meta_type_by_name(keyspace_meta, udt_name.c_str()); + if (datatype == NULL) { boost::this_thread::sleep_for(boost::chrono::milliseconds(100)); } } - BOOST_REQUIRE(!udt_field_names.empty()); + BOOST_REQUIRE(datatype != NULL); } public: - UDTTests() : test_utils::SingleSessionTest(1, 0), schema_(NULL) { + UDTTests() : test_utils::SingleSessionTest(1, 0), schema_meta_(NULL) { test_utils::execute_query(session, str(boost::format(test_utils::CREATE_KEYSPACE_SIMPLE_FORMAT) % test_utils::SIMPLE_KEYSPACE % "1")); test_utils::execute_query(session, str(boost::format("USE %s") % test_utils::SIMPLE_KEYSPACE)); } @@ -91,7 +94,9 @@ struct UDTTests : public test_utils::SingleSessionTest { */ test_utils::CassUserTypePtr new_udt(const std::string &udt_name) { verify_user_type(udt_name); - const CassDataType* datatype = cass_schema_get_udt(schema_.get(), test_utils::SIMPLE_KEYSPACE.c_str(), udt_name.c_str()); + const CassKeyspaceMeta* keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta_.get(), test_utils::SIMPLE_KEYSPACE.c_str()); + BOOST_REQUIRE(keyspace_meta != NULL); + const CassDataType* datatype = cass_keyspace_meta_type_by_name(keyspace_meta, udt_name.c_str()); BOOST_REQUIRE(datatype != NULL); return test_utils::CassUserTypePtr(cass_user_type_new_from_data_type(datatype)); } diff --git a/test/integration_tests/src/test_utils.hpp b/test/integration_tests/src/test_utils.hpp index 00e8237b1..b98b1afd0 100644 --- a/test/integration_tests/src/test_utils.hpp +++ b/test/integration_tests/src/test_utils.hpp @@ -367,10 +367,10 @@ struct Deleter { }; template<> -struct Deleter { - void operator()(const CassSchema* ptr) { +struct Deleter { + void operator()(const CassSchemaMeta* ptr) { if (ptr != NULL) { - cass_schema_free(ptr); + cass_schema_meta_free(ptr); } } }; @@ -404,7 +404,7 @@ typedef CassSharedPtr CassUserTypePtr; typedef CassSharedPtr CassPreparedPtr; typedef CassSharedPtr CassBatchPtr; typedef CassSharedPtr CassUuidGenPtr; -typedef CassSharedPtr CassSchemaPtr; +typedef CassSharedPtr CassSchemaMetaPtr; typedef CassSharedPtr CassCustomPayloadPtr; template diff --git a/test/unit_tests/src/test_copy_on_write.cpp b/test/unit_tests/src/test_copy_on_write.cpp index f4fb2a48b..527c0f635 100644 --- a/test/unit_tests/src/test_copy_on_write.cpp +++ b/test/unit_tests/src/test_copy_on_write.cpp @@ -19,8 +19,11 @@ #endif #include "copy_on_write_ptr.hpp" +#include "ref_counted.hpp" #include +#include +#include BOOST_AUTO_TEST_SUITE(copy_on_write) @@ -45,5 +48,57 @@ BOOST_AUTO_TEST_CASE(simple) BOOST_CHECK(const_vec.operator->() == ptr); } +BOOST_AUTO_TEST_CASE(nested) +{ + struct Table : public cass::RefCounted { + typedef cass::SharedRefPtr
Ptr; + typedef std::map Map; + + Table(const std::string name) + : name(name) { } + + std::string name; + private: + DISALLOW_COPY_AND_ASSIGN(Table); + }; + + struct Keyspace { + typedef std::map Map; + + Keyspace() + : tables(new Table::Map) { } + + void add_table(const Table::Ptr& table) { + (*tables)[table->name] = table; + } + + cass::CopyOnWritePtr tables; + }; + + struct Metadata { + Metadata() + : keyspaces(new Keyspace::Map) { } + + Keyspace* get_or_create(const std::string& name) { + return &(*keyspaces)[name]; + } + + cass::CopyOnWritePtr keyspaces; + }; + + Metadata m1; + Keyspace* k1 = m1.get_or_create("k1"); + k1->add_table(Table::Ptr(new Table("t1"))); + k1->add_table(Table::Ptr(new Table("t2"))); + + Keyspace* k2 = m1.get_or_create("k2"); + k2->add_table(Table::Ptr(new Table("t1"))); + k2->add_table(Table::Ptr(new Table("t2"))); + + Metadata m2 = m1; + + m1.get_or_create("k1")->add_table(Table::Ptr(new Table("t2"))); +} + BOOST_AUTO_TEST_SUITE_END() From 3ebad40c6b552d08d611a5305cea72a60c12dd38 Mon Sep 17 00:00:00 2001 From: Michael Fero Date: Thu, 15 Oct 2015 21:47:00 +0000 Subject: [PATCH 05/13] Fixing GCC and Windows builds --- src/metadata.cpp | 2 +- test/unit_tests/src/test_copy_on_write.cpp | 56 +++++++++++----------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/metadata.cpp b/src/metadata.cpp index c4299cdf6..1f3578f38 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -411,7 +411,7 @@ void Metadata::clear() { } const MetadataField* MetadataBase::get_field(const std::string& name) const { - typename MetadataField::Map::const_iterator it = fields_.find(name); + MetadataField::Map::const_iterator it = fields_.find(name); if (it == fields_.end()) return NULL; return &it->second; } diff --git a/test/unit_tests/src/test_copy_on_write.cpp b/test/unit_tests/src/test_copy_on_write.cpp index 527c0f635..5dd187975 100644 --- a/test/unit_tests/src/test_copy_on_write.cpp +++ b/test/unit_tests/src/test_copy_on_write.cpp @@ -48,44 +48,44 @@ BOOST_AUTO_TEST_CASE(simple) BOOST_CHECK(const_vec.operator->() == ptr); } -BOOST_AUTO_TEST_CASE(nested) -{ - struct Table : public cass::RefCounted
{ - typedef cass::SharedRefPtr
Ptr; - typedef std::map Map; +struct Table : public cass::RefCounted
{ + typedef cass::SharedRefPtr
Ptr; + typedef std::map Map; - Table(const std::string name) - : name(name) { } + Table(const std::string name) + : name(name) { } - std::string name; - private: - DISALLOW_COPY_AND_ASSIGN(Table); - }; + std::string name; +private: + DISALLOW_COPY_AND_ASSIGN(Table); +}; - struct Keyspace { - typedef std::map Map; +struct Keyspace { + typedef std::map Map; - Keyspace() - : tables(new Table::Map) { } + Keyspace() + : tables(new Table::Map) { } - void add_table(const Table::Ptr& table) { - (*tables)[table->name] = table; - } + void add_table(const Table::Ptr& table) { + (*tables)[table->name] = table; + } - cass::CopyOnWritePtr tables; - }; + cass::CopyOnWritePtr tables; +}; - struct Metadata { - Metadata() - : keyspaces(new Keyspace::Map) { } +struct Metadata { + Metadata() + : keyspaces(new Keyspace::Map) { } - Keyspace* get_or_create(const std::string& name) { - return &(*keyspaces)[name]; - } + Keyspace* get_or_create(const std::string& name) { + return &(*keyspaces)[name]; + } - cass::CopyOnWritePtr keyspaces; - }; + cass::CopyOnWritePtr keyspaces; +}; +BOOST_AUTO_TEST_CASE(nested) +{ Metadata m1; Keyspace* k1 = m1.get_or_create("k1"); k1->add_table(Table::Ptr(new Table("t1"))); From 0a9350bcd450aaed2e0fe90a29b7abd7f05d9cc2 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Fri, 16 Oct 2015 14:11:39 -0700 Subject: [PATCH 06/13] Use const for iterators in cass_iterator_get_...() functions --- include/cassandra.h | 14 ++++++------- src/iterator.cpp | 49 ++++++++++++++++++++++---------------------- src/map_iterator.hpp | 4 ++-- src/row_iterator.hpp | 2 +- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index 49353dfec..a98b5d157 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -6168,7 +6168,7 @@ cass_iterator_next(CassIterator* iterator); * @return A row */ CASS_EXPORT const CassRow* -cass_iterator_get_row(CassIterator* iterator); +cass_iterator_get_row(const CassIterator* iterator); /** * Gets the column value at the row iterator's current position. @@ -6182,7 +6182,7 @@ cass_iterator_get_row(CassIterator* iterator); * @return A value */ CASS_EXPORT const CassValue* -cass_iterator_get_column(CassIterator* iterator); +cass_iterator_get_column(const CassIterator* iterator); /** * Gets the value at a collection or tuple iterator's current position. @@ -6196,7 +6196,7 @@ cass_iterator_get_column(CassIterator* iterator); * @return A value */ CASS_EXPORT const CassValue* -cass_iterator_get_value(CassIterator* iterator); +cass_iterator_get_value(const CassIterator* iterator); /** * Gets the key at the map iterator's current position. @@ -6210,7 +6210,7 @@ cass_iterator_get_value(CassIterator* iterator); * @return A value */ CASS_EXPORT const CassValue* -cass_iterator_get_map_key(CassIterator* iterator); +cass_iterator_get_map_key(const CassIterator* iterator); /** @@ -6225,7 +6225,7 @@ cass_iterator_get_map_key(CassIterator* iterator); * @return A value */ CASS_EXPORT const CassValue* -cass_iterator_get_map_value(CassIterator* iterator); +cass_iterator_get_map_value(const CassIterator* iterator); /** * Gets the field name at the user type defined iterator's current position. @@ -6241,7 +6241,7 @@ cass_iterator_get_map_value(CassIterator* iterator); * @return CASS_OK if successful, otherwise error occurred */ CASS_EXPORT CassError -cass_iterator_get_user_type_field_name(CassIterator* iterator, +cass_iterator_get_user_type_field_name(const CassIterator* iterator, const char** name, size_t* name_length); @@ -6257,7 +6257,7 @@ cass_iterator_get_user_type_field_name(CassIterator* iterator, * @return A value */ CASS_EXPORT const CassValue* -cass_iterator_get_user_type_field_value(CassIterator* iterator); +cass_iterator_get_user_type_field_value(const CassIterator* iterator); /** * Gets the keyspace metadata entry at the iterator's current position. diff --git a/src/iterator.cpp b/src/iterator.cpp index 33150e02e..8f37e620c 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -25,6 +25,14 @@ extern "C" { +void cass_iterator_free(CassIterator* iterator) { + delete iterator->from(); +} + +cass_bool_t cass_iterator_next(CassIterator* iterator) { + return static_cast(iterator->from()->next()); +} + CassIteratorType cass_iterator_type(CassIterator* iterator) { return iterator->type(); } @@ -65,81 +73,72 @@ CassIterator* cass_iterator_from_user_type(const CassValue* value) { return CassIterator::to(new cass::UserTypeIterator(value)); } -CassError cass_iterator_get_user_type_field_name(CassIterator* iterator, - const char** name, - size_t* name_length) { +CassError cass_iterator_get_user_type_field_name(const CassIterator* iterator, + const char** name, + size_t* name_length) { if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE) { return CASS_ERROR_LIB_BAD_PARAMS; } cass::StringRef field_name - = static_cast( + = static_cast( iterator->from())->field_name(); *name = field_name.data(); *name_length = field_name.size(); return CASS_OK; } -const CassValue* cass_iterator_get_user_type_field_value(CassIterator* iterator) { +const CassValue* cass_iterator_get_user_type_field_value(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE) { return NULL; } return CassValue::to( - static_cast( + static_cast( iterator->from())->field_value()); } - -void cass_iterator_free(CassIterator* iterator) { - delete iterator->from(); -} - -cass_bool_t cass_iterator_next(CassIterator* iterator) { - return static_cast(iterator->from()->next()); -} - -const CassRow* cass_iterator_get_row(CassIterator* iterator) { +const CassRow* cass_iterator_get_row(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_RESULT) { return NULL; } return CassRow::to( - static_cast( + static_cast( iterator->from())->row()); } -const CassValue* cass_iterator_get_column(CassIterator* iterator) { +const CassValue* cass_iterator_get_column(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_ROW) { return NULL; } return CassValue::to( - static_cast( + static_cast( iterator->from())->column()); } -const CassValue* cass_iterator_get_value(CassIterator* iterator) { +const CassValue* cass_iterator_get_value(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_COLLECTION && iterator->type() != CASS_ITERATOR_TYPE_TUPLE) { return NULL; } return CassValue::to( - static_cast( + static_cast( iterator->from())->value()); } -const CassValue* cass_iterator_get_map_key(CassIterator* iterator) { +const CassValue* cass_iterator_get_map_key(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_MAP) { return NULL; } return CassValue::to( - static_cast( + static_cast( iterator->from())->key()); } -const CassValue* cass_iterator_get_map_value(CassIterator* iterator) { +const CassValue* cass_iterator_get_map_value(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_MAP) { return NULL; } return CassValue::to( - static_cast( + static_cast( iterator->from())->value()); } diff --git a/src/map_iterator.hpp b/src/map_iterator.hpp index 031b39376..cbea953a1 100644 --- a/src/map_iterator.hpp +++ b/src/map_iterator.hpp @@ -35,12 +35,12 @@ class MapIterator : public Iterator { virtual bool next(); - const Value* key() { + const Value* key() const { assert(index_ >= 0 && index_ < count_); return &key_; } - const Value* value() { + const Value* value() const { assert(index_ >= 0 && index_ < count_); return &value_; } diff --git a/src/row_iterator.hpp b/src/row_iterator.hpp index 3c666daac..bcb71aa12 100644 --- a/src/row_iterator.hpp +++ b/src/row_iterator.hpp @@ -37,7 +37,7 @@ class RowIterator : public Iterator { return true; } - const Value* column() { + const Value* column() const { assert(index_ >= 0 && static_cast(index_) < row_->values.size()); return &row_->values[index_]; } From 82860c5664b8462518c2a341921d932e94ada136 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Fri, 16 Oct 2015 15:19:26 -0700 Subject: [PATCH 07/13] Removed CassMetaField type and made the CassUserType iterator more consistent --- examples/schema_meta/schema_meta.c | 10 +-- examples/udt/udt.c | 4 +- include/cassandra.h | 82 +++++++++---------- src/external_types.hpp | 1 - src/iterator.cpp | 14 ++-- src/metadata.cpp | 71 ++++++++-------- src/metadata.hpp | 4 +- src/replication_strategy.cpp | 12 +-- src/replication_strategy.hpp | 10 +-- ...rator.cpp => user_type_field_iterator.cpp} | 6 +- ...rator.hpp => user_type_field_iterator.hpp} | 6 +- .../src/test_schema_metadata.cpp | 23 +++--- test/integration_tests/src/test_udts.cpp | 14 ++-- 13 files changed, 125 insertions(+), 132 deletions(-) rename src/{user_type_iterator.cpp => user_type_field_iterator.cpp} (87%) rename src/{user_type_iterator.hpp => user_type_field_iterator.hpp} (91%) diff --git a/examples/schema_meta/schema_meta.c b/examples/schema_meta/schema_meta.c index 806a87a25..2506e692b 100644 --- a/examples/schema_meta/schema_meta.c +++ b/examples/schema_meta/schema_meta.c @@ -130,7 +130,7 @@ int main() { void print_schema_value(const CassValue* value); void print_schema_list(const CassValue* value); void print_schema_map(const CassValue* value); -void print_meta_field(const CassMetaField* field, int indent); +void print_meta_field(const CassIterator* iterator, int indent); void print_meta_fields(CassIterator* iterator, int indent); void print_column_meta(const CassColumnMeta* meta, int indent); @@ -228,13 +228,13 @@ void print_schema_map(const CassValue* value) { cass_iterator_free(iterator); } -void print_meta_field(const CassMetaField* field, int indent) { +void print_meta_field(const CassIterator* iterator, int indent) { const char* name; size_t name_length; const CassValue* value; - cass_meta_field_name(field, &name, &name_length); - value = cass_meta_field_value(field); + cass_iterator_get_meta_field_name(iterator, &name, &name_length); + value = cass_iterator_get_meta_field_value(iterator); print_indent(indent); printf("%.*s: ", (int)name_length, name); @@ -244,7 +244,7 @@ void print_meta_field(const CassMetaField* field, int indent) { void print_meta_fields(CassIterator* iterator, int indent) { while (cass_iterator_next(iterator)) { - print_meta_field(cass_iterator_get_meta_field(iterator), indent); + print_meta_field(iterator, indent); } cass_iterator_free(iterator); } diff --git a/examples/udt/udt.c b/examples/udt/udt.c index 27ab51d02..e41025b5e 100644 --- a/examples/udt/udt.c +++ b/examples/udt/udt.c @@ -172,7 +172,7 @@ CassError select_from_udt(CassSession* session) { const CassRow* row = cass_iterator_get_row(rows); const CassValue* id_value = cass_row_get_column_by_name(row, "id"); const CassValue* address_value = cass_row_get_column_by_name(row, "address"); - CassIterator* fields = cass_iterator_from_user_type(address_value); + CassIterator* fields = cass_iterator_fields_from_user_type(address_value); cass_value_get_uuid(id_value, &id); cass_uuid_string(id, id_str); @@ -201,7 +201,7 @@ CassError select_from_udt(CassSession* session) { CassIterator* phone_numbers = cass_iterator_from_collection(field_value); while (cass_iterator_next(phone_numbers)) { const CassValue* phone_value = cass_iterator_get_value(phone_numbers); - CassIterator* phone_fields = cass_iterator_from_user_type(phone_value); + CassIterator* phone_fields = cass_iterator_fields_from_user_type(phone_value); assert(cass_value_type(phone_value) == CASS_VALUE_TYPE_UDT); while (cass_iterator_next(phone_fields)) { const CassValue* phone_number_value = cass_iterator_get_user_type_field_value(phone_fields); diff --git a/include/cassandra.h b/include/cassandra.h index a98b5d157..962af5a45 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -324,7 +324,6 @@ typedef struct CassSchemaMeta_ CassSchemaMeta; typedef struct CassKeyspaceMeta_ CassKeyspaceMeta; typedef struct CassTableMeta_ CassTableMeta; typedef struct CassColumnMeta_ CassColumnMeta; -typedef struct CassMetaField_ CassMetaField; typedef enum CassColumnType_ { CASS_COLUMN_TYPE_REGULAR, @@ -499,7 +498,7 @@ typedef enum CassIteratorType_ { CASS_ITERATOR_TYPE_COLLECTION, CASS_ITERATOR_TYPE_MAP, CASS_ITERATOR_TYPE_TUPLE, - CASS_ITERATOR_TYPE_USER_TYPE, + CASS_ITERATOR_TYPE_USER_TYPE_FIELD, CASS_ITERATOR_TYPE_META_FIELD, CASS_ITERATOR_TYPE_KEYSPACE_META, CASS_ITERATOR_TYPE_TABLE_META, @@ -1656,9 +1655,9 @@ cass_keyspace_meta_name(const CassKeyspaceMeta* keyspace_meta, * * @param[in] keyspace_meta * @param[in] name - * @return A schema metadata field. NULL if the field does not exist. + * @return A metadata field value. NULL if the field does not exist. */ -CASS_EXPORT const CassMetaField* +CASS_EXPORT const CassValue* cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, const char* name); @@ -1675,7 +1674,7 @@ cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, * * @see cass_keyspace_meta_field_by_name() */ -CASS_EXPORT const CassMetaField* +CASS_EXPORT const CassValue* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* name, size_t name_length); @@ -1816,9 +1815,9 @@ cass_table_meta_clustering_key(const CassTableMeta* table_meta, * * @param[in] table_meta * @param[in] name - * @return A schema metadata field. NULL if the field does not exist. + * @return A metadata field value. NULL if the field does not exist. */ -CASS_EXPORT const CassMetaField* +CASS_EXPORT const CassValue* cass_table_meta_field_by_name(const CassTableMeta* table_meta, const char* name); @@ -1835,7 +1834,7 @@ cass_table_meta_field_by_name(const CassTableMeta* table_meta, * * @see cass_table_meta_field_by_name() */ -CASS_EXPORT const CassMetaField* +CASS_EXPORT const CassValue* cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, const char* name, size_t name_length); @@ -1883,9 +1882,9 @@ cass_column_meta_data_type(const CassColumnMeta* column_meta); * * @param[in] column_meta * @param[in] name - * @return A schema metadata field. NULL if the field does not exist. + * @return A metadata field value. NULL if the field does not exist. */ -CASS_EXPORT const CassMetaField* +CASS_EXPORT const CassValue* cass_column_meta_field_by_name(const CassColumnMeta* column_meta, const char* name); @@ -1902,36 +1901,11 @@ cass_column_meta_field_by_name(const CassColumnMeta* column_meta, * * @see cass_column_meta_field_by_name() */ -CASS_EXPORT const CassMetaField* +CASS_EXPORT const CassValue* cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, const char* name, size_t name_length); -/** - * Gets the name for a metadata field - * - * @public @memberof CassMetaField - * - * @param[in] field - * @param[out] name The name of the metadata data field - * @param[out] name_length - */ -CASS_EXPORT void -cass_meta_field_name(const CassMetaField* field, - const char** name, - size_t* name_length); - -/** - * Gets the value for a metadata field - * - * @public @memberof CassMetaField - * - * @param[in] field - * @return The value of the metadata data field - */ -CASS_EXPORT const CassValue* -cass_meta_field_value(const CassMetaField* field); - /*********************************************************************************** * * SSL @@ -6038,7 +6012,7 @@ cass_iterator_from_tuple(const CassValue* value); * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_from_user_type(const CassValue* value); +cass_iterator_fields_from_user_type(const CassValue* value); /** * Creates a new iterator for the specified schema metadata. @@ -6094,7 +6068,8 @@ cass_iterator_types_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); * @param[in] keyspace_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_meta_field() + * @see cass_iterator_get_meta_field_name() + * @see cass_iterator_get_meta_field_value() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* @@ -6124,7 +6099,8 @@ cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta); * @param[in] table_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_meta_field() + * @see cass_iterator_get_meta_field_name() + * @see cass_iterator_get_meta_field_value() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* @@ -6139,7 +6115,8 @@ cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta); * @param[in] column_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_meta_field() + * @see cass_iterator_get_meta_field_name() + * @see cass_iterator_get_meta_field_value() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* @@ -6316,7 +6293,7 @@ CASS_EXPORT const CassColumnMeta* cass_iterator_get_column_meta(const CassIterator* iterator); /** - * Gets the metadata field entry at the iterator's current position. + * Gets the metadata field name at the iterator's current position. * * Calling cass_iterator_next() will invalidate the previous * value returned by this method. @@ -6324,11 +6301,28 @@ cass_iterator_get_column_meta(const CassIterator* iterator); * @public @memberof CassIterator * * @param[in] iterator - * @return A metadata field + * @param[out] name + * @param[out] name_length + * @return CASS_OK if successful, otherwise error occurred */ -CASS_EXPORT const CassMetaField* -cass_iterator_get_meta_field(const CassIterator* iterator); +CASS_EXPORT CassError +cass_iterator_get_meta_field_name(const CassIterator* iterator, + const char** name, + size_t* name_length); +/** + * Gets the metadata field value at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A metadata field value + */ +CASS_EXPORT const CassValue* +cass_iterator_get_meta_field_value(const CassIterator* iterator); /*********************************************************************************** * diff --git a/src/external_types.hpp b/src/external_types.hpp index 398e014d3..3be460edb 100644 --- a/src/external_types.hpp +++ b/src/external_types.hpp @@ -72,7 +72,6 @@ EXTERNAL_TYPE(cass::Row, CassRow); EXTERNAL_TYPE(cass::Value, CassValue); EXTERNAL_TYPE(cass::SslContext, CassSsl); EXTERNAL_TYPE(cass::Metadata::SchemaSnapshot, CassSchemaMeta); -EXTERNAL_TYPE(cass::MetadataField, CassMetaField); EXTERNAL_TYPE(cass::KeyspaceMetadata, CassKeyspaceMeta); EXTERNAL_TYPE(cass::TableMetadata, CassTableMeta); EXTERNAL_TYPE(cass::ColumnMetadata, CassColumnMeta); diff --git a/src/iterator.cpp b/src/iterator.cpp index 8f37e620c..32018b8cf 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -21,7 +21,7 @@ #include "map_iterator.hpp" #include "result_iterator.hpp" #include "row_iterator.hpp" -#include "user_type_iterator.hpp" +#include "user_type_field_iterator.hpp" extern "C" { @@ -66,21 +66,21 @@ CassIterator* cass_iterator_from_map(const CassValue* value) { return CassIterator::to(new cass::MapIterator(value)); } -CassIterator* cass_iterator_from_user_type(const CassValue* value) { +CassIterator* cass_iterator_fields_from_user_type(const CassValue* value) { if (value->is_null() || !value->is_user_type()) { return NULL; } - return CassIterator::to(new cass::UserTypeIterator(value)); + return CassIterator::to(new cass::UserTypeFieldIterator(value)); } CassError cass_iterator_get_user_type_field_name(const CassIterator* iterator, const char** name, size_t* name_length) { - if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE) { + if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE_FIELD) { return CASS_ERROR_LIB_BAD_PARAMS; } cass::StringRef field_name - = static_cast( + = static_cast( iterator->from())->field_name(); *name = field_name.data(); *name_length = field_name.size(); @@ -88,11 +88,11 @@ CassError cass_iterator_get_user_type_field_name(const CassIterator* iterator, } const CassValue* cass_iterator_get_user_type_field_value(const CassIterator* iterator) { - if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE) { + if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE_FIELD) { return NULL; } return CassValue::to( - static_cast( + static_cast( iterator->from())->field_value()); } diff --git a/src/metadata.cpp b/src/metadata.cpp index 1f3578f38..61258df48 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -83,14 +83,14 @@ void cass_keyspace_meta_name(const CassKeyspaceMeta* keyspace_meta, *name_length = keyspace_meta->name().size(); } -const CassMetaField* cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, +const CassValue* cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, const char* name) { - return CassMetaField::to(keyspace_meta->get_field(name)); + return CassValue::to(keyspace_meta->get_field(name)); } -const CassMetaField* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, +const CassValue* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* name, size_t name_length) { - return CassMetaField::to(keyspace_meta->get_field(std::string(name, name_length))); + return CassValue::to(keyspace_meta->get_field(std::string(name, name_length))); } @@ -115,14 +115,14 @@ CassUuid cass_table_meta_id(const CassTableMeta* table_meta) { return table_meta->id(); } -const CassMetaField* cass_table_meta_field_by_name(const CassTableMeta* table_meta, +const CassValue* cass_table_meta_field_by_name(const CassTableMeta* table_meta, const char* name) { - return CassMetaField::to(table_meta->get_field(name)); + return CassValue::to(table_meta->get_field(name)); } -const CassMetaField* cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, +const CassValue* cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, const char* name, size_t name_length) { - return CassMetaField::to(table_meta->get_field(std::string(name, name_length))); + return CassValue::to(table_meta->get_field(std::string(name, name_length))); } size_t cass_table_meta_column_count(const CassTableMeta* table_meta) { @@ -179,27 +179,16 @@ cass_bool_t cass_column_meta_is_reversed(const CassColumnMeta* column_meta) { return column_meta->is_reversed() ? cass_true : cass_false; } -const CassMetaField* +const CassValue* cass_column_meta_field_by_name(const CassColumnMeta* column_meta, const char* name) { - return CassMetaField::to(column_meta->get_field(name)); + return CassValue::to(column_meta->get_field(name)); } -const CassMetaField* +const CassValue* cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, const char* name, size_t name_length) { - return CassMetaField::to(column_meta->get_field(std::string(name, name_length))); -} - -void cass_meta_field_name(const CassMetaField* field, - const char** name, size_t* name_length) { - const std::string& n = field->name(); - *name = n.data(); - *name_length = n.length(); -} - -const CassValue* cass_meta_field_value(const CassMetaField* field) { - return CassValue::to(field->value()); + return CassValue::to(column_meta->get_field(std::string(name, name_length))); } CassIterator* cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta) { @@ -266,14 +255,26 @@ const CassColumnMeta* cass_iterator_get_column_meta(const CassIterator* iterator iterator->from())->column()); } -CASS_EXPORT const CassMetaField* -cass_iterator_get_meta_field(const CassIterator* iterator) { +CassError cass_iterator_get_meta_field_name(const CassIterator* iterator, + const char** name, + size_t* name_length) { + if (iterator->type() != CASS_ITERATOR_TYPE_META_FIELD) { + return CASS_ERROR_LIB_BAD_PARAMS; + } + const cass::MetadataField* field = + static_cast(iterator->from())->field(); + *name = field->name().data(); + *name_length = field->name().size(); + return CASS_OK; +} + +const CassValue* cass_iterator_get_meta_field_value(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_META_FIELD) { return NULL; } - return CassMetaField::to( + return CassValue::to( static_cast( - iterator->from())->field()); + iterator->from())->field()->value()); } } // extern "C" @@ -410,16 +411,16 @@ void Metadata::clear() { token_map_.clear(); } -const MetadataField* MetadataBase::get_field(const std::string& name) const { +const Value* MetadataBase::get_field(const std::string& name) const { MetadataField::Map::const_iterator it = fields_.find(name); if (it == fields_.end()) return NULL; - return &it->second; + return it->second.value(); } std::string MetadataBase::get_string_field(const std::string& name) const { - const MetadataField* field = get_field(name); - if (field == NULL) return std::string(); - return field->value()->to_string(); + const Value* value = get_field(name); + if (value == NULL) return std::string(); + return value->to_string(); } const Value* MetadataBase::add_field(const SharedRefPtr& buffer, const Row* row, const std::string& name) { @@ -673,10 +674,10 @@ void TableMetadata::build_keys() { } void TableMetadata::key_aliases(KeyAliases* output) const { - const MetadataField* aliases = get_field("key_aliases"); + const Value* aliases = get_field("key_aliases"); if (aliases != NULL) { - output->reserve(aliases->value()->count()); - CollectionIterator itr(aliases->value()); + output->reserve(aliases->count()); + CollectionIterator itr(aliases); while (itr.next()) { output->push_back(itr.value()->to_string()); } diff --git a/src/metadata.hpp b/src/metadata.hpp index 05ef91844..8469db368 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -144,7 +144,7 @@ class MetadataBase { const std::string name() const { return name_; } - const MetadataField* get_field(const std::string& name) const; + const Value* get_field(const std::string& name) const; std::string get_string_field(const std::string& name) const; Iterator* iterator_fields() const { return new MetadataFieldIterator(fields_); } @@ -286,7 +286,7 @@ class KeyspaceMetadata : public MetadataBase { void drop_type(const std::string& type_name); std::string strategy_class() const { return get_string_field("strategy_class"); } - const MetadataField* strategy_options() const { return get_field("strategy_options"); } + const Value* strategy_options() const { return get_field("strategy_options"); } private: CopyOnWritePtr tables_; diff --git a/src/replication_strategy.cpp b/src/replication_strategy.cpp index 7a9d54bcb..4a2f66a43 100644 --- a/src/replication_strategy.cpp +++ b/src/replication_strategy.cpp @@ -46,7 +46,7 @@ SharedRefPtr ReplicationStrategy::from_keyspace_meta(const const std::string NetworkTopologyStrategy::STRATEGY_CLASS("NetworkTopologyStrategy"); NetworkTopologyStrategy::NetworkTopologyStrategy(const std::string& strategy_class, - const MetadataField* strategy_options) + const Value* strategy_options) : ReplicationStrategy(strategy_class) { build_dc_replicas(strategy_options, &replication_factors_); } @@ -135,10 +135,10 @@ void NetworkTopologyStrategy::tokens_to_replicas(const TokenHostMap& primary, To } } -void NetworkTopologyStrategy::build_dc_replicas(const MetadataField* strategy_options, +void NetworkTopologyStrategy::build_dc_replicas(const Value* strategy_options, NetworkTopologyStrategy::DCReplicaCountMap* output) { if (strategy_options != NULL) { - MapIterator itr(strategy_options->value()); + MapIterator itr(strategy_options); while (itr.next()) { StringRef key = itr.key()->to_string_ref(); StringRef value = itr.value()->to_string_ref(); @@ -156,7 +156,7 @@ void NetworkTopologyStrategy::build_dc_replicas(const MetadataField* strategy_op const std::string SimpleStrategy::STRATEGY_CLASS("SimpleStrategy"); SimpleStrategy::SimpleStrategy(const std::string& strategy_class, - const MetadataField* strategy_options) + const Value* strategy_options) : ReplicationStrategy(strategy_class) , replication_factor_(0) { replication_factor_ = get_replication_factor(strategy_options); @@ -187,9 +187,9 @@ void SimpleStrategy::tokens_to_replicas(const TokenHostMap& primary, TokenReplic } } -size_t SimpleStrategy::get_replication_factor(const MetadataField* strategy_options) { +size_t SimpleStrategy::get_replication_factor(const Value* strategy_options) { if (strategy_options != NULL) { - MapIterator itr(strategy_options->value()); + MapIterator itr(strategy_options); while (itr.next()) { StringRef key = itr.key()->to_string_ref(); StringRef value = itr.value()->to_string_ref(); diff --git a/src/replication_strategy.hpp b/src/replication_strategy.hpp index 08c641191..c3f5888bc 100644 --- a/src/replication_strategy.hpp +++ b/src/replication_strategy.hpp @@ -26,7 +26,7 @@ namespace cass { class KeyspaceMetadata; -class MetadataField; +class Value; typedef std::vector Token; typedef std::map > TokenHostMap; @@ -55,7 +55,7 @@ class NetworkTopologyStrategy : public ReplicationStrategy { static const std::string STRATEGY_CLASS; NetworkTopologyStrategy(const std::string& strategy_class, - const MetadataField* strategy_options); + const Value* strategy_options); virtual ~NetworkTopologyStrategy() {} virtual bool equal(const KeyspaceMetadata& ks_meta); @@ -68,7 +68,7 @@ class NetworkTopologyStrategy : public ReplicationStrategy { , replication_factors_(replication_factors) {} private: - static void build_dc_replicas(const MetadataField* strategy_options, DCReplicaCountMap* dc_replicas); + static void build_dc_replicas(const Value* strategy_options, DCReplicaCountMap* dc_replicas); DCReplicaCountMap replication_factors_; }; @@ -78,7 +78,7 @@ class SimpleStrategy : public ReplicationStrategy { static const std::string STRATEGY_CLASS; SimpleStrategy(const std::string& strategy_class, - const MetadataField* strategy_options); + const Value* strategy_options); virtual ~SimpleStrategy() {} virtual bool equal(const KeyspaceMetadata& ks_meta); @@ -91,7 +91,7 @@ class SimpleStrategy : public ReplicationStrategy { , replication_factor_(replication_factor) {} private: - static size_t get_replication_factor(const MetadataField* strategy_options); + static size_t get_replication_factor(const Value* strategy_options); size_t replication_factor_; }; diff --git a/src/user_type_iterator.cpp b/src/user_type_field_iterator.cpp similarity index 87% rename from src/user_type_iterator.cpp rename to src/user_type_field_iterator.cpp index 2f9398b80..46bdbbaf9 100644 --- a/src/user_type_iterator.cpp +++ b/src/user_type_field_iterator.cpp @@ -14,13 +14,13 @@ limitations under the License. */ -#include "user_type_iterator.hpp" +#include "user_type_field_iterator.hpp" #include "serialization.hpp" namespace cass { -bool UserTypeIterator::next() { +bool UserTypeFieldIterator::next() { if (next_ == end_) { return false; } @@ -29,7 +29,7 @@ bool UserTypeIterator::next() { return true; } -char* UserTypeIterator::decode_field(char* position) { +char* UserTypeFieldIterator::decode_field(char* position) { int32_t size; char* buffer = decode_int32(position, size); value_ = Value(user_type_value_->protocol_version(), current_->type, buffer, size); diff --git a/src/user_type_iterator.hpp b/src/user_type_field_iterator.hpp similarity index 91% rename from src/user_type_iterator.hpp rename to src/user_type_field_iterator.hpp index b22bb0829..713c9c814 100644 --- a/src/user_type_iterator.hpp +++ b/src/user_type_field_iterator.hpp @@ -25,10 +25,10 @@ namespace cass { -class UserTypeIterator : public Iterator { +class UserTypeFieldIterator : public Iterator { public: - UserTypeIterator(const Value* user_type_value) - : Iterator(CASS_ITERATOR_TYPE_USER_TYPE) + UserTypeFieldIterator(const Value* user_type_value) + : Iterator(CASS_ITERATOR_TYPE_USER_TYPE_FIELD) , user_type_value_(user_type_value) , position_(user_type_value->data()) { SharedRefPtr user_type(user_type_value->data_type()); diff --git a/test/integration_tests/src/test_schema_metadata.cpp b/test/integration_tests/src/test_schema_metadata.cpp index fd7e1ebe2..2d10b1c80 100644 --- a/test/integration_tests/src/test_schema_metadata.cpp +++ b/test/integration_tests/src/test_schema_metadata.cpp @@ -142,9 +142,8 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { // all fields present, nothing extra std::set observed; while (cass_iterator_next(itr.get())) { - const CassMetaField* field = cass_iterator_get_meta_field(itr.get()); CassString name; - cass_meta_field_name(field, &name.data, &name.length); + cass_iterator_get_meta_field_name(itr.get(), &name.data, &name.length); observed.insert(std::string(name.data, name.length)); } @@ -298,13 +297,13 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { verify_fields(test_utils::CassIteratorPtr(cass_iterator_fields_from_table_meta(table_meta)), table_fields()); verify_fields_by_name(table_meta, table_fields()); - verify_value(cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "keyspace_name")), SIMPLE_STRATEGY_KEYSPACE_NAME); - verify_value(cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "columnfamily_name")), ALL_DATA_TYPES_TABLE_NAME); + verify_value(cass_table_meta_field_by_name(table_meta, "keyspace_name"), SIMPLE_STRATEGY_KEYSPACE_NAME); + verify_value(cass_table_meta_field_by_name(table_meta, "columnfamily_name"), ALL_DATA_TYPES_TABLE_NAME); // not going for every field, just making sure one of each type (fixed, list, map) is correctly added - verify_value(cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "comment")), COMMENT); + verify_value(cass_table_meta_field_by_name(table_meta, "comment"), COMMENT); - const CassValue* value = cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "compression_parameters")); + const CassValue* value = cass_table_meta_field_by_name(table_meta, "compression_parameters"); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_MAP); BOOST_REQUIRE_GE(cass_value_item_count(value), 1ul); test_utils::CassIteratorPtr itr(cass_iterator_from_map(value)); @@ -323,10 +322,10 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { BOOST_CHECK(param_found); if ((version.major >= 2 && version.minor >= 2) || version.major >= 3) { - value = cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "cf_id")); + value = cass_table_meta_field_by_name(table_meta, "cf_id"); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_UUID); } else { - value = cass_meta_field_value(cass_table_meta_field_by_name(table_meta, "key_aliases")); + value = cass_table_meta_field_by_name(table_meta, "key_aliases"); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_LIST); BOOST_CHECK_GE(cass_value_item_count(value), 1ul); } @@ -378,10 +377,10 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { const CassKeyspaceMeta* ks_meta = schema_get_keyspace(name); verify_fields(test_utils::CassIteratorPtr(cass_iterator_fields_from_keyspace_meta(ks_meta)), keyspace_fields()); verify_fields_by_name(ks_meta, keyspace_fields()); - verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "keyspace_name")), name); - verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "durable_writes")), (cass_bool_t)durable_writes); - verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "strategy_class")), strategy_class); - verify_value(cass_meta_field_value(cass_keyspace_meta_field_by_name(ks_meta, "strategy_options")), strategy_options); + verify_value(cass_keyspace_meta_field_by_name(ks_meta, "keyspace_name"), name); + verify_value(cass_keyspace_meta_field_by_name(ks_meta, "durable_writes"), (cass_bool_t)durable_writes); + verify_value(cass_keyspace_meta_field_by_name(ks_meta, "strategy_class"), strategy_class); + verify_value(cass_keyspace_meta_field_by_name(ks_meta, "strategy_options"), strategy_options); BOOST_CHECK(!cass_keyspace_meta_table_by_name(ks_meta, "some bogus entry")); } diff --git a/test/integration_tests/src/test_udts.cpp b/test/integration_tests/src/test_udts.cpp index e1b7fccc2..7098ba2c1 100644 --- a/test/integration_tests/src/test_udts.cpp +++ b/test/integration_tests/src/test_udts.cpp @@ -128,7 +128,7 @@ struct UDTTests : public test_utils::SingleSessionTest { // Ensure the value is a UDT and create the iterator for the validation BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_UDT); BOOST_REQUIRE_EQUAL(cass_value_item_count(value), 2); - test_utils::CassIteratorPtr iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr iterator(cass_iterator_fields_from_user_type(value)); // Verify alias field name BOOST_REQUIRE(cass_iterator_next(iterator.get())); @@ -153,7 +153,7 @@ struct UDTTests : public test_utils::SingleSessionTest { void verify_phone_udt(const CassValue* value, CassString expected_alias, CassString expected_number) { // Verify field names for phone UDT and create the iterator for validation verify_phone_udt_field_names(value); - test_utils::CassIteratorPtr iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr iterator(cass_iterator_fields_from_user_type(value)); // Verify alias result BOOST_REQUIRE(cass_iterator_next(iterator.get())); @@ -181,7 +181,7 @@ struct UDTTests : public test_utils::SingleSessionTest { // Ensure the value is a UDT and create the iterator for the validation BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_UDT); BOOST_REQUIRE_EQUAL(cass_value_item_count(value), 3); - test_utils::CassIteratorPtr iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr iterator(cass_iterator_fields_from_user_type(value)); // Verify street field name BOOST_REQUIRE(cass_iterator_next(iterator.get())); @@ -213,7 +213,7 @@ struct UDTTests : public test_utils::SingleSessionTest { void verify_address_udt(const CassValue* value, CassString expected_street, cass_int32_t expected_zip, PhoneMap expected_phone_numbers) { // Verify field names for address UDT and create the iterator for validation verify_address_udt_field_names(value); - test_utils::CassIteratorPtr iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr iterator(cass_iterator_fields_from_user_type(value)); // Verify street result BOOST_REQUIRE(cass_iterator_next(iterator.get())); @@ -348,7 +348,7 @@ BOOST_AUTO_TEST_CASE(read_write) { const CassValue* value = cass_row_get_column(row, 0); BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_UDT); tester.verify_address_udt_field_names(value); - test_utils::CassIteratorPtr iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr iterator(cass_iterator_fields_from_user_type(value)); // Verify street result BOOST_REQUIRE(cass_iterator_next(iterator.get())); const CassValue* street_value = cass_iterator_get_user_type_field_value(iterator.get()); @@ -482,7 +482,7 @@ BOOST_AUTO_TEST_CASE(text_types) { BOOST_REQUIRE_EQUAL(cass_value_type(value), CASS_VALUE_TYPE_UDT); // Verify the parent key - test_utils::CassIteratorPtr iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr iterator(cass_iterator_fields_from_user_type(value)); BOOST_REQUIRE(cass_iterator_next(iterator.get())); const CassValue* name_value = cass_iterator_get_user_type_field_value(iterator.get()); BOOST_REQUIRE_EQUAL(cass_value_type(name_value), CASS_VALUE_TYPE_VARCHAR); @@ -497,7 +497,7 @@ BOOST_AUTO_TEST_CASE(text_types) { BOOST_REQUIRE_EQUAL(cass_value_item_count(value), 2); // Verify the values in the nested UDT - test_utils::CassIteratorPtr nested_iterator(cass_iterator_from_user_type(value)); + test_utils::CassIteratorPtr nested_iterator(cass_iterator_fields_from_user_type(value)); BOOST_REQUIRE(cass_iterator_next(nested_iterator.get())); const CassValue* value_value = cass_iterator_get_user_type_field_value(nested_iterator.get()); BOOST_REQUIRE_EQUAL(cass_value_type(value_value), CASS_VALUE_TYPE_INT); From 289d54fb7702c9db4b353d68c027995b850b0028 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Fri, 16 Oct 2015 15:23:37 -0700 Subject: [PATCH 08/13] Added descriptions for new metadata types --- include/cassandra.h | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index 962af5a45..b35933a9e 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -321,16 +321,27 @@ typedef struct CassSsl_ CassSsl; * A snapshot of the schema's metadata. */ typedef struct CassSchemaMeta_ CassSchemaMeta; + +/** + * @struct CassKeyspaceMeta + * + * Keyspace metadata + */ typedef struct CassKeyspaceMeta_ CassKeyspaceMeta; + +/** + * @struct CassTableMeta + * + * Table metadata + */ typedef struct CassTableMeta_ CassTableMeta; -typedef struct CassColumnMeta_ CassColumnMeta; -typedef enum CassColumnType_ { - CASS_COLUMN_TYPE_REGULAR, - CASS_COLUMN_TYPE_PARTITION_KEY, - CASS_COLUMN_TYPE_CLUSTERING_KEY, - CASS_COLUMN_TYPE_STATIC -} CassColumnType; +/** + * @struct CassColumnMeta + * + * Column metadata + */ +typedef struct CassColumnMeta_ CassColumnMeta; /** * @struct CassUuidGen @@ -530,6 +541,13 @@ typedef enum CassSslVerifyFlags { CASS_SSL_VERIFY_PEER_IDENTITY } CassSslVerifyFlags; +typedef enum CassColumnType_ { + CASS_COLUMN_TYPE_REGULAR, + CASS_COLUMN_TYPE_PARTITION_KEY, + CASS_COLUMN_TYPE_CLUSTERING_KEY, + CASS_COLUMN_TYPE_STATIC +} CassColumnType; + typedef enum CassErrorSource_ { CASS_ERROR_SOURCE_NONE, CASS_ERROR_SOURCE_LIB, From 61c81e1fafcd5a39032da3904588fa96b8d1f11f Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Tue, 20 Oct 2015 08:15:34 -0700 Subject: [PATCH 09/13] All column meta constructor should initialize members --- src/metadata.cpp | 5 ++++- src/metadata.hpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/metadata.cpp b/src/metadata.cpp index 61258df48..07d075f80 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -698,7 +698,10 @@ void TableMetadata::key_aliases(KeyAliases* output) const { ColumnMetadata::ColumnMetadata(const std::string& name, int version, const SharedRefPtr& buffer, const Row* row) - : MetadataBase(name) { + : MetadataBase(name) + , type_(CASS_COLUMN_TYPE_REGULAR) + , position_(-1) + , is_reversed_(false) { const Value* value; add_field(buffer, row, "keyspace_name"); diff --git a/src/metadata.hpp b/src/metadata.hpp index 8469db368..ac6455037 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -183,7 +183,7 @@ class ColumnMetadata : public MetadataBase, public RefCounted { ColumnMetadata(const std::string& name) : MetadataBase(name) , type_(CASS_COLUMN_TYPE_REGULAR) - , position_(0) + , position_(-1) , is_reversed_(false) { } ColumnMetadata(const std::string& name, From 2722981ef4743a337242adcfdb0a92b15ba48a10 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Wed, 14 Oct 2015 16:34:40 -0700 Subject: [PATCH 10/13] Added UDF/UDA metadata support --- include/cassandra.h | 452 ++++++++++++++++++++- src/collection_iterator.hpp | 6 +- src/control_connection.cpp | 80 +++- src/control_connection.hpp | 34 +- src/data_type.hpp | 88 +++- src/event_response.cpp | 18 +- src/event_response.hpp | 53 +-- src/external_types.hpp | 2 + src/metadata.cpp | 495 ++++++++++++++++++++++- src/metadata.hpp | 114 +++++- src/result_response.cpp | 4 +- src/serialization.hpp | 11 +- src/string_ref.hpp | 4 + src/type_parser.cpp | 64 +-- src/type_parser.hpp | 12 +- src/value.cpp | 19 + src/value.hpp | 2 + test/unit_tests/src/test_type_parser.cpp | 26 +- 18 files changed, 1342 insertions(+), 142 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index b35933a9e..f0574eb2d 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -287,6 +287,16 @@ typedef struct CassValue_ CassValue; */ typedef struct CassDataType_ CassDataType; +/** + * @struct CassFunctionMeta + */ +typedef struct CassFunctionMeta_ CassFunctionMeta; + +/** + * @struct CassAggregateMeta + */ +typedef struct CassAggregateMeta_ CassAggregateMeta; + /** * @struct CassCollection * @@ -514,6 +524,8 @@ typedef enum CassIteratorType_ { CASS_ITERATOR_TYPE_KEYSPACE_META, CASS_ITERATOR_TYPE_TABLE_META, CASS_ITERATOR_TYPE_TYPE_META, + CASS_ITERATOR_TYPE_FUNCTION_META, + CASS_ITERATOR_TYPE_AGGREGATE_META, CASS_ITERATOR_TYPE_COLUMN_META } CassIteratorType; @@ -1619,7 +1631,6 @@ cass_keyspace_meta_table_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* table, size_t table_length); - /** * Gets the data type for the provided type name. * @@ -1652,6 +1663,80 @@ cass_keyspace_meta_type_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* type, size_t type_length); +/** + * Gets the function metadata for the provided function name. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] name + * @param[in] arguments + * + * @return The data function for a user defined function. NULL if function does not exist. + */ +CASS_EXPORT const CassFunctionMeta* +cass_keyspace_meta_function_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name, + const char* arguments); + +/** + * Same as cass_keyspace_meta_function_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] name + * @param[in] name_length + * @param[in] arguments + * @param[in] argument_length + * @return same as cass_keyspace_meta_function_by_name() + * + * @see cass_keyspace_meta_function_by_name() + */ +CASS_EXPORT const CassFunctionMeta* +cass_keyspace_meta_function_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, + size_t name_length, + const char* arguments, + size_t arguments_length); + +/** + * Gets the aggregate metadata for the provided aggregate name. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] name + * @param[in] arguments + * + * @return The data aggregate for a user defined aggregate. NULL if aggregate does not exist. + */ +CASS_EXPORT const CassAggregateMeta* +cass_keyspace_meta_aggregate_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name, + const char* arguments); + +/** + * Same as cass_keyspace_meta_aggregate_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] name + * @param[in] name_length + * @return same as cass_keyspace_meta_aggregate_by_name() + * + * @see cass_keyspace_meta_aggregate_by_name() + */ +CASS_EXPORT const CassAggregateMeta* +cass_keyspace_meta_aggregate_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, + size_t name_length, + const char* arguments, + size_t arguments_length); + /** * Gets the name of the keyspace. * @@ -1890,7 +1975,7 @@ cass_column_meta_type(const CassColumnMeta* column_meta); * @param[in] column_meta * @return The column's data type. */ -CASS_EXPORT CassDataType* +CASS_EXPORT const CassDataType* cass_column_meta_data_type(const CassColumnMeta* column_meta); /** @@ -1924,6 +2009,281 @@ cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, const char* name, size_t name_length); +/** + * Gets the name of the function. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_function_meta_name(const CassFunctionMeta* function_meta, + const char** name, + size_t* name_length); + +/** + * Gets the full name of the function. The full name includes the + * function's name and the function's signature: + * "name(type1 type2.. typeN)". + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @param[out] full_name + * @param[out] full_name_length + */ +CASS_EXPORT void +cass_function_meta_full_name(const CassFunctionMeta* function_meta, + const char** full_name, + size_t* full_name_length); + +/** + * Gets the body of the function. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @param[out] body + * @param[out] body_length + */ +CASS_EXPORT void +cass_function_meta_body(const CassFunctionMeta* function_meta, + const char** body, + size_t* body_length); + +/** + * Gets the language of the function. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @param[out] language + * @param[out] language_length + */ +CASS_EXPORT void +cass_function_meta_language(const CassFunctionMeta* function_meta, + const char** language, + size_t* language_length); + +/** + * Gets whether a function is called on "null". + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @return cass_true if a function is called on null, otherwise cass_false. + */ +CASS_EXPORT cass_bool_t +cass_function_meta_called_on_null_input(const CassFunctionMeta* function_meta); + +/** + * Gets the number of arguments this function takes. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @return The number of arguments. + */ +CASS_EXPORT size_t +cass_function_meta_argument_count(const CassFunctionMeta* function_meta); + +/** + * Gets the function's argument name and type for the provided index. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @param[in] index + * @param[out] name + * @param[out] name_lenght + * @param[out] type + * @return CASS_OK if successful, otherwise an error occurred + */ +CASS_EXPORT CassError +cass_function_meta_argument(const CassFunctionMeta* function_meta, + size_t index, + const char** name, + size_t* name_length, + const CassDataType** type); + +/** + * Gets the function's argument and type for the provided name. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @param[in] name + * @return A data type. NULL if the argument does not exist. + */ +CASS_EXPORT const CassDataType* +cass_function_meta_argument_type_by_name(const CassFunctionMeta* function_meta, + const char* name); + +/** + * Same as cass_function_meta_argument_type_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassFunctionMeta + * + * @param[in] column_meta + * @param[in] name + * @param[in] name_length + * @return same as cass_function_meta_argument_type_by_name() + * + * @see cass_function_meta_argument_type_by_name() + */ +CASS_EXPORT const CassDataType* +cass_function_meta_argument_type_by_name_n(const CassFunctionMeta* function_meta, + const char* name, + size_t name_length); + +/** + * Gets the return type of the function. + * + * @public @memberof CassFunctionMeta + * + * @param[in] function_meta + * @return The data type returned by the function. + */ +CASS_EXPORT const CassDataType* +cass_function_meta_return_type(const CassFunctionMeta* function_meta); + +/** + * Gets the name of the aggregate. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_aggregate_meta_name(const CassAggregateMeta* aggregate_meta, + const char** name, + size_t* name_length); + +/** + * Gets the full name of the aggregate. The full name includes the + * aggregate's name and the aggregate's signature: + * "name(type1 type2.. typeN)". + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @param[out] full_name + * @param[out] full_name_length + */ +CASS_EXPORT void +cass_aggregate_meta_full_name(const CassAggregateMeta* aggregate_meta, + const char** full_name, + size_t* full_name_length); + +/** + * Gets the number of arguments this aggregate takes. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @return The number of arguments. + */ +CASS_EXPORT size_t +cass_aggregate_meta_argument_count(const CassAggregateMeta* aggregate_meta); + +/** + * Gets the aggregate's argument type for the provided index. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @param[in] index + * @return The data type for argument. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassDataType* +cass_aggregate_meta_argument_type(const CassAggregateMeta* aggregate_meta, + size_t index); + +/** + * Gets the return type of the aggregate. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @return The data type returned by the aggregate. + */ +CASS_EXPORT const CassDataType* +cass_aggregate_meta_return_type(const CassAggregateMeta* aggregate_meta); + +/** + * Gets the state type of the aggregate. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @return The data type of the aggregate's state. + */ +CASS_EXPORT const CassDataType* +cass_aggregate_meta_state_type(const CassAggregateMeta* aggregate_meta); + +/** + * Gets the function metadata for the aggregate's state function. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @return The function metadata for the state function. + */ +CASS_EXPORT const CassFunctionMeta* +cass_aggregate_meta_state_func(const CassAggregateMeta* aggregate_meta); + +/** + * Gets the function metadata for the aggregates's final function. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @return The function metadata for the final function. + */ +CASS_EXPORT const CassFunctionMeta* +cass_aggregate_meta_final_func(const CassAggregateMeta* aggregate_meta); + +/** + * Gets the initial condition value for the aggregate. + * + * @public @memberof CassAggregateMeta + * + * @param[in] aggregate_meta + * @return The value of the intial condidtion. + */ +CASS_EXPORT const CassValue* +cass_aggregate_meta_init_cond(const CassAggregateMeta* aggregate_meta); + +/** + * Gets the name for a metadata field + * + * @public @memberof CassMetaField + * + * @param[in] field + * @param[out] name The name of the metadata data field + * @param[out] name_length + */ +CASS_EXPORT void +cass_meta_field_name(const CassMetaField* field, + const char** name, + size_t* name_length); + +/** + * Gets the value for a metadata field + * + * @public @memberof CassMetaField + * + * @param[in] field + * @return The value of the metadata data field + */ +CASS_EXPORT const CassValue* +cass_meta_field_value(const CassMetaField* field); + /*********************************************************************************** * * SSL @@ -6077,6 +6437,36 @@ cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); CASS_EXPORT CassIterator* cass_iterator_types_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); +/** + * Creates a new iterator for the specified keyspace metadata. + * This can be used to iterate over functions. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_function_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_functions_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); + +/** + * Creates a new iterator for the specified keyspace metadata. + * This can be used to iterate over aggregates. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_aggregate_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_aggregates_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); + /** * Creates a new iterator for the specified keyspace metadata. * This can be used to iterate over field entries. @@ -6140,6 +6530,36 @@ cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta); CASS_EXPORT CassIterator* cass_iterator_fields_from_column_meta(const CassColumnMeta* column_meta); +/** + * Creates a new iterator for the specified function metadata. + * This can be used to iterate over field entries. + * + * @public @memberof CassColumnMeta + * + * @param[in] function_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_meta_field() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_fields_from_function_meta(const CassFunctionMeta* function_meta); + +/** + * Creates a new iterator for the specified aggregate metadata. + * This can be used to iterate over field entries. + * + * @public @memberof CassColumnMeta + * + * @param[in] aggregate_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_meta_field() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_fields_from_aggregate_meta(const CassAggregateMeta* aggregate_meta); + /** * Advance the iterator to the next row, column or collection item. * @@ -6296,6 +6716,34 @@ cass_iterator_get_table_meta(const CassIterator* iterator); CASS_EXPORT const CassDataType* cass_iterator_get_type_meta(const CassIterator* iterator); +/** + * Gets the function metadata entry at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A function metadata entry + */ +CASS_EXPORT const CassFunctionMeta* +cass_iterator_get_function_meta(const CassIterator* iterator); + +/** + * Gets the aggregate metadata entry at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A aggregate metadata entry + */ +CASS_EXPORT const CassAggregateMeta* +cass_iterator_get_aggregate_meta(const CassIterator* iterator); + /** * Gets the column metadata entry at the iterator's current position. * diff --git a/src/collection_iterator.hpp b/src/collection_iterator.hpp index 6a3338270..fbbe2dd30 100644 --- a/src/collection_iterator.hpp +++ b/src/collection_iterator.hpp @@ -81,9 +81,9 @@ class TupleIterator : public ValueIterator { const Value* tuple_; char* position_; - DataTypeVec::const_iterator next_; - DataTypeVec::const_iterator current_; - DataTypeVec::const_iterator end_; + DataType::Vec::const_iterator next_; + DataType::Vec::const_iterator current_; + DataType::Vec::const_iterator end_; }; } // namespace cass diff --git a/src/control_connection.cpp b/src/control_connection.cpp index 7b94a7245..c7dbc8a4b 100644 --- a/src/control_connection.cpp +++ b/src/control_connection.cpp @@ -42,6 +42,8 @@ #define SELECT_COLUMN_FAMILIES "SELECT * FROM system.schema_columnfamilies" #define SELECT_COLUMNS "SELECT * FROM system.schema_columns" #define SELECT_USERTYPES "SELECT * FROM system.schema_usertypes" +#define SELECT_FUNCTIONS "SELECT * FROM system.schema_functions" +#define SELECT_AGGREGATES "SELECT * FROM system.schema_aggregates" namespace cass { @@ -312,6 +314,13 @@ void ControlConnection::on_event(EventResponse* response) { case EventResponse::TYPE: refresh_type(response->keyspace(), response->target()); break; + case EventResponse::FUNCTION: + case EventResponse::AGGREGATE: + refresh_function(response->keyspace(), + response->target(), + response->arg_types(), + response->schema_change() == EventResponse::AGGREGATE); + break; } break; @@ -326,7 +335,7 @@ void ControlConnection::on_event(EventResponse* response) { break; case EventResponse::TYPE: session_->metadata().drop_type(response->keyspace().to_string(), - response->target().to_string()); + response->target().to_string()); break; } break; @@ -355,6 +364,10 @@ void ControlConnection::query_meta_all() { if (protocol_version_ >= 3) { handler->execute_query(SELECT_USERTYPES); } + if (protocol_version_ >= 4) { + handler->execute_query(SELECT_FUNCTIONS); + handler->execute_query(SELECT_AGGREGATES); + } } } @@ -442,7 +455,10 @@ void ControlConnection::on_query_meta_all(ControlConnection* control_connection, if (control_connection->protocol_version_ >= 3) { session->metadata().update_types(static_cast(responses[5].get())); } - + if (control_connection->protocol_version_ >= 4) { + session->metadata().update_functions(static_cast(responses[6].get())); + session->metadata().update_aggregates(static_cast(responses[7].get())); + } session->metadata().swap_to_back_and_update_front(); } @@ -698,14 +714,70 @@ void ControlConnection::on_refresh_type(ControlConnection* control_connection, Response* response) { ResultResponse* result = static_cast(response); if (result->row_count() == 0) { - LOG_ERROR("No row found for keyspace %s and type %s in system schema table.", + LOG_ERROR("No row found for keyspace %s and type %s in system schema.", keyspace_and_type_names.first.c_str(), - keyspace_and_type_names.first.c_str()); + keyspace_and_type_names.second.c_str()); return; } control_connection->session_->metadata().update_types(result); } +void ControlConnection::refresh_function(const StringRef& keyspace_name, + const StringRef& function_name, + const StringRefVec& arg_types, + bool is_aggregate) { + + std::string query; + if (is_aggregate) { + query.assign(SELECT_AGGREGATES); + query.append(" WHERE keyspace_name=? AND aggregate_name=? AND signature=?"); + } else { + query.assign(SELECT_FUNCTIONS); + query.append(" WHERE keyspace_name=? AND function_name=? AND signature=?"); + } + + // TODO: Fix this logging statment + LOG_DEBUG("Refreshing function or aggregate %s", query.c_str()); + + SharedRefPtr request(new QueryRequest(query, 3)); + SharedRefPtr signature(new Collection(CASS_COLLECTION_TYPE_LIST, arg_types.size())); + + for (StringRefVec::const_iterator i = arg_types.begin(), + end = arg_types.end(); + i != end; + ++i) { + signature->append(CassString(i->data(), i->size())); + } + + request->set(0, CassString(keyspace_name.data(), keyspace_name.size())); + request->set(1, CassString(function_name.data(), function_name.size())); + request->set(2, signature.get()); + + connection_->write( + new ControlHandler(request.get(), + this, + ControlConnection::on_refresh_function, + RefreshFunctionData(keyspace_name, function_name, arg_types, is_aggregate))); +} + +void ControlConnection::on_refresh_function(ControlConnection* control_connection, + const RefreshFunctionData& data, + Response* response) { + ResultResponse* result = static_cast(response); + if (result->row_count() == 0) { + // TODO: Fix this error + LOG_ERROR("No row found for keyspace %s and function %s in system schema.", + data.keyspace.c_str(), + data.function.c_str()); + return; + } + if (data.is_aggregate) { + control_connection->session_->metadata().update_aggregates(result); + } else { + control_connection->session_->metadata().update_functions(result); + } +} + bool ControlConnection::handle_query_invalid_response(Response* response) { if (check_error_or_invalid_response("ControlConnection", CQL_OPCODE_RESULT, response)) { diff --git a/src/control_connection.hpp b/src/control_connection.hpp index 3c3dd3c73..341589aa9 100644 --- a/src/control_connection.hpp +++ b/src/control_connection.hpp @@ -153,6 +153,30 @@ class ControlConnection : public Connection::Listener { bool is_new_node; }; + struct RefreshFunctionData { + typedef std::vector StringVec; + + RefreshFunctionData(StringRef keyspace, + StringRef function, + const StringRefVec& arg_types, + bool is_aggregate) + : keyspace(keyspace.to_string()) + , function(function.to_string()) + , is_aggregate(is_aggregate) { + this->arg_types.reserve(arg_types.size()); + for (StringRefVec::const_iterator i = arg_types.begin(), + end = arg_types.end(); + i != end; ++i) { + this->arg_types.push_back(i->to_string()); + } + } + + std::string keyspace; + std::string function; + StringVec arg_types; + bool is_aggregate; + }; + void schedule_reconnect(uint64_t ms = 0); void reconnect(bool retry_current_host); @@ -196,11 +220,19 @@ class ControlConnection : public Connection::Listener { const MultipleRequestHandler::ResponseVec& responses); void refresh_type(const StringRef& keyspace_name, - const StringRef& type_name); + const StringRef& type_name); static void on_refresh_type(ControlConnection* control_connection, const std::pair& keyspace_and_type_names, Response* response); + void refresh_function(const StringRef& keyspace_name, + const StringRef& function_name, + const StringRefVec& arg_types, + bool is_aggregate); + static void on_refresh_function(ControlConnection* control_connection, + const RefreshFunctionData& data, + Response* response); + private: State state_; Session* session_; diff --git a/src/data_type.hpp b/src/data_type.hpp index b9910375c..97a06c0f5 100644 --- a/src/data_type.hpp +++ b/src/data_type.hpp @@ -65,6 +65,9 @@ inline bool equals_both_not_empty(const std::string& s1, class DataType : public RefCounted { public: + typedef SharedRefPtr Ptr; + typedef std::vector Vec; + static const SharedRefPtr NIL; DataType(CassValueType value_type) @@ -112,6 +115,36 @@ class DataType : public RefCounted { return new DataType(value_type_); } + virtual std::string to_string() const { + switch (value_type_) { + case CASS_VALUE_TYPE_ASCII: return "ascii"; + case CASS_VALUE_TYPE_BIGINT: return "bigint"; + case CASS_VALUE_TYPE_BLOB: return "blob"; + case CASS_VALUE_TYPE_BOOLEAN: return "boolean"; + case CASS_VALUE_TYPE_COUNTER: return "counter"; + case CASS_VALUE_TYPE_DECIMAL: return "decimal"; + case CASS_VALUE_TYPE_DOUBLE: return "double"; + case CASS_VALUE_TYPE_FLOAT: return "float"; + case CASS_VALUE_TYPE_INT: return "int"; + case CASS_VALUE_TYPE_TEXT: return "text"; + case CASS_VALUE_TYPE_TIMESTAMP: return "timestamp"; + case CASS_VALUE_TYPE_UUID: return "uuid"; + case CASS_VALUE_TYPE_VARCHAR: return "varchar"; + case CASS_VALUE_TYPE_VARINT: return "varint"; + case CASS_VALUE_TYPE_TIMEUUID: return "timeuuid"; + case CASS_VALUE_TYPE_INET: return "inet"; + case CASS_VALUE_TYPE_DATE: return "date"; + case CASS_VALUE_TYPE_TIME: return "time"; + case CASS_VALUE_TYPE_SMALL_INT: return "smallint"; + case CASS_VALUE_TYPE_TINY_INT: return "tinyint"; + case CASS_VALUE_TYPE_LIST: return "list"; + case CASS_VALUE_TYPE_MAP: return "map"; + case CASS_VALUE_TYPE_SET: return "set"; + case CASS_VALUE_TYPE_TUPLE: return "tuple"; + default: return ""; + } + } + private: int protocol_version_; CassValueType value_type_; @@ -120,8 +153,6 @@ class DataType : public RefCounted { DISALLOW_COPY_AND_ASSIGN(DataType); }; -typedef std::vector > DataTypeVec; - class CustomType : public DataType { public: CustomType() @@ -150,6 +181,10 @@ class CustomType : public DataType { return new CustomType(class_name_); } + virtual std::string to_string() const { + return class_name_; + } + private: std::string class_name_; }; @@ -159,15 +194,29 @@ class SubTypesDataType : public DataType { SubTypesDataType(CassValueType type) : DataType(type) { } - SubTypesDataType(CassValueType type, const DataTypeVec& types) + SubTypesDataType(CassValueType type, const DataType::Vec& types) : DataType(type) , types_(types) { } - DataTypeVec& types() { return types_; } - const DataTypeVec& types() const { return types_; } + DataType::Vec& types() { return types_; } + const DataType::Vec& types() const { return types_; } + + virtual std::string to_string() const { + std::string str(DataType::to_string()); + str.push_back('<'); + bool first = true; + for (DataType::Vec::const_iterator i = types_.begin(), + end = types_.end(); + i != end; ++i) { + if (!first) str.append(", "); + str.append((*i)->to_string()); + } + str.push_back('>'); + return str; + } protected: - DataTypeVec types_; + DataType::Vec types_; }; class CollectionType : public SubTypesDataType { @@ -181,7 +230,7 @@ class CollectionType : public SubTypesDataType { types_.reserve(types_count); } - CollectionType(CassValueType collection_type, const DataTypeVec& types) + CollectionType(CassValueType collection_type, const DataType::Vec& types) : SubTypesDataType(collection_type, types) { } virtual bool equals(const SharedRefPtr& data_type) const { @@ -215,23 +264,24 @@ class CollectionType : public SubTypesDataType { } public: - static SharedRefPtr list(SharedRefPtr element_type) { - DataTypeVec types; + static SharedRefPtr list(SharedRefPtr element_type) { + DataType::Vec types; types.push_back(element_type); - return SharedRefPtr(new CollectionType(CASS_VALUE_TYPE_LIST, types)); + return SharedRefPtr(new CollectionType(CASS_VALUE_TYPE_LIST, types)); } - static SharedRefPtr set(SharedRefPtr element_type) { - DataTypeVec types; + static SharedRefPtr set(SharedRefPtr element_type) { + DataType::Vec types; types.push_back(element_type); - return SharedRefPtr(new CollectionType(CASS_VALUE_TYPE_SET, types)); + return SharedRefPtr(new CollectionType(CASS_VALUE_TYPE_SET, types)); } - static SharedRefPtr map(SharedRefPtr key_type, SharedRefPtr value_type) { - DataTypeVec types; + static SharedRefPtr map(SharedRefPtr key_type, + SharedRefPtr value_type) { + DataType::Vec types; types.push_back(key_type); types.push_back(value_type); - return SharedRefPtr(new CollectionType(CASS_VALUE_TYPE_MAP, types)); + return SharedRefPtr(new CollectionType(CASS_VALUE_TYPE_MAP, types)); } }; @@ -240,7 +290,7 @@ class TupleType : public SubTypesDataType { TupleType() : SubTypesDataType(CASS_VALUE_TYPE_TUPLE) { } - TupleType(const DataTypeVec& types) + TupleType(const DataType::Vec& types) : SubTypesDataType(CASS_VALUE_TYPE_TUPLE, types) { } virtual bool equals(const SharedRefPtr& data_type) const { @@ -359,6 +409,10 @@ class UserType : public DataType { return new UserType(keyspace_, type_name_, fields_.entries()); } + virtual std::string to_string() const { + return type_name_; + } + private: std::string keyspace_; std::string type_name_; diff --git a/src/event_response.cpp b/src/event_response.cpp index a943a98a9..b389746ab 100644 --- a/src/event_response.cpp +++ b/src/event_response.cpp @@ -70,9 +70,9 @@ bool EventResponse::decode(int version, char* buffer, size_t size) { if (version <= 2) { // Version 1 and 2: ...
([string][string]) - pos = decode_string(pos, &keyspace_, keyspace_size_); - decode_string(pos, &target_, target_size_); - schema_change_target_ = target_size_ == 0 ? KEYSPACE : TABLE; + pos = decode_string(pos, &keyspace_); + decode_string(pos, &target_); + schema_change_target_ = target_.size() == 0 ? KEYSPACE : TABLE; } else { // Version 3+: ... // = [string] @@ -86,15 +86,23 @@ bool EventResponse::decode(int version, char* buffer, size_t size) { schema_change_target_ = TABLE; } else if (target == "TYPE") { schema_change_target_ = TYPE; + } else if (target == "FUNCTION") { + schema_change_target_ = FUNCTION; + } else if (target == "AGGREGATE") { + schema_change_target_ = AGGREGATE; } else { return false; } - pos = decode_string(pos, &keyspace_, keyspace_size_); + pos = decode_string(pos, &keyspace_); if (schema_change_target_ == TABLE || schema_change_target_ == TYPE) { - decode_string(pos, &target_, target_size_); + decode_string(pos, &target_); + } else if (schema_change_target_ == FUNCTION || + schema_change_target_ == AGGREGATE) { + pos = decode_string(pos, &target_); + decode_stringlist(pos, arg_types_); } } } else { diff --git a/src/event_response.hpp b/src/event_response.hpp index 0e19ce895..d49ffa3ad 100644 --- a/src/event_response.hpp +++ b/src/event_response.hpp @@ -47,7 +47,9 @@ class EventResponse : public Response { enum SchemaChangeTarget { KEYSPACE = 1, TABLE, - TYPE + TYPE, + FUNCTION, + AGGREGATE }; EventResponse() @@ -56,43 +58,19 @@ class EventResponse : public Response { , topology_change_(0) , status_change_(0) , schema_change_(0) - , schema_change_target_(0) - , keyspace_(NULL) - , keyspace_size_(0) - , target_(NULL) - , target_size_(0) {} + , schema_change_target_(0) { } bool decode(int version, char* buffer, size_t size); int event_type() const { return event_type_; } - - int topology_change() const { - return topology_change_; - } - - int status_change() const { - return status_change_; - } - - const Address& affected_node() const { - return affected_node_; - } - - int schema_change() const { - return schema_change_; - } - - int schema_change_target() const { - return schema_change_target_; - } - - StringRef keyspace() const { - return StringRef(keyspace_, keyspace_size_); - } - - StringRef target() const { - return StringRef(target_, target_size_); - } + int topology_change() const { return topology_change_; } + int status_change() const { return status_change_; } + const Address& affected_node() const { return affected_node_; } + int schema_change() const { return schema_change_; } + int schema_change_target() const { return schema_change_target_; } + StringRef keyspace() const { return keyspace_; } + StringRef target() const { return target_; } + const StringRefVec& arg_types() const { return arg_types_; } private: int event_type_; @@ -103,10 +81,9 @@ class EventResponse : public Response { int schema_change_; int schema_change_target_; - char* keyspace_; - size_t keyspace_size_; - char* target_; - size_t target_size_; + StringRef keyspace_; + StringRef target_; + StringRefVec arg_types_; }; } // namespace cass diff --git a/src/external_types.hpp b/src/external_types.hpp index 3be460edb..3e6002be5 100644 --- a/src/external_types.hpp +++ b/src/external_types.hpp @@ -75,6 +75,8 @@ EXTERNAL_TYPE(cass::Metadata::SchemaSnapshot, CassSchemaMeta); EXTERNAL_TYPE(cass::KeyspaceMetadata, CassKeyspaceMeta); EXTERNAL_TYPE(cass::TableMetadata, CassTableMeta); EXTERNAL_TYPE(cass::ColumnMetadata, CassColumnMeta); +EXTERNAL_TYPE(cass::FunctionMetadata, CassFunctionMeta); +EXTERNAL_TYPE(cass::AggregateMetadata, CassAggregateMeta); EXTERNAL_TYPE(cass::UuidGen, CassUuidGen); EXTERNAL_TYPE(cass::Tuple, CassTuple); EXTERNAL_TYPE(cass::UserTypeValue, CassUserType); diff --git a/src/metadata.cpp b/src/metadata.cpp index 07d075f80..889f5535d 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -33,6 +33,23 @@ #include +static std::string& append_arguments(std::string& full_name, const std::string& arguments) { + full_name.push_back('('); + bool first = true; + std::istringstream stream(arguments); + while (!stream.eof()) { + std::string argument; + std::getline(stream, argument, ','); + if (!cass::trim(argument).empty()) { + if (!first) full_name.push_back(','); + full_name.append(argument); + first = false; + } + } + full_name.push_back(')'); + return full_name; +} + extern "C" { void cass_schema_meta_free(const CassSchemaMeta* schema_meta) { @@ -77,6 +94,44 @@ const CassDataType* cass_keyspace_meta_type_by_name_n(const CassKeyspaceMeta* ke return CassDataType::to(keyspace_meta->get_type(std::string(type, type_length))); } +const CassFunctionMeta* cass_keyspace_meta_function_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name, + const char* arguments) { + std::string full_function_name(name); + return CassFunctionMeta::to(keyspace_meta->get_function( + append_arguments(full_function_name, std::string(arguments)))); +} + + +const CassFunctionMeta* cass_keyspace_meta_function_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, + size_t name_length, + const char* arguments, + size_t arguments_length) { + std::string full_function_name(name, name_length); + return CassFunctionMeta::to(keyspace_meta->get_function( + append_arguments(full_function_name, std::string(arguments, arguments_length)))); +} + +const CassAggregateMeta* cass_keyspace_meta_aggregate_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name, + const char* arguments) { + std::string full_aggregate_name(name); + return CassAggregateMeta::to(keyspace_meta->get_aggregate( + append_arguments(full_aggregate_name, std::string(arguments)))); +} + +const CassAggregateMeta* cass_keyspace_meta_aggregate_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, + size_t name_length, + const char* arguments, + size_t arguments_length) { + std::string full_aggregate_name(name, name_length); + return CassAggregateMeta::to(keyspace_meta->get_aggregate( + append_arguments(full_aggregate_name, std::string(arguments, arguments_length)))); +} + + void cass_keyspace_meta_name(const CassKeyspaceMeta* keyspace_meta, const char** name, size_t* name_length) { *name = keyspace_meta->name().data(); @@ -171,7 +226,7 @@ CassColumnType cass_column_meta_type(const CassColumnMeta* column_meta) { return column_meta->type(); } -CassDataType* cass_column_meta_data_type(const CassColumnMeta* column_meta) { +const CassDataType* cass_column_meta_data_type(const CassColumnMeta* column_meta) { return CassDataType::to(column_meta->data_type().get()); } @@ -191,6 +246,130 @@ cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, return CassValue::to(column_meta->get_field(std::string(name, name_length))); } +void cass_function_meta_name(const CassFunctionMeta* function_meta, + const char** name, + size_t* name_length) { + *name = function_meta->simple_name().data(); + *name_length = function_meta->simple_name().size(); +} + +void cass_function_meta_full_name(const CassFunctionMeta* function_meta, + const char** full_name, + size_t* full_name_length) { + *full_name = function_meta->name().data(); + *full_name_length = function_meta->name().size(); +} + +void cass_function_meta_body(const CassFunctionMeta* function_meta, + const char** body, + size_t* body_length) { + *body = function_meta->body().data(); + *body_length = function_meta->body().size(); +} + +void cass_function_meta_language(const CassFunctionMeta* function_meta, + const char** language, + size_t* language_length) { + *language = function_meta->language().data(); + *language_length = function_meta->language().size(); +} + +cass_bool_t cass_function_meta_called_on_null_input(const CassFunctionMeta* function_meta) { + return function_meta->called_on_null_input() ? cass_true : cass_false; +} + +size_t cass_function_meta_argument_count(const CassFunctionMeta* function_meta) { + return function_meta->args().size(); +} + +CassError cass_function_meta_argument(const CassFunctionMeta* function_meta, + size_t index, + const char** name, + size_t* name_length, + const CassDataType** type) { + if (index >= function_meta->args().size()) { + return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS; + } + const cass::FunctionMetadata::Argument& arg = function_meta->args()[index]; + *name = arg.name.data(); + *name_length = arg.name.size(); + *type = CassDataType::to(arg.type.get()); + return CASS_OK; +} + +const CassDataType* cass_function_meta_argument_type_by_name(const CassFunctionMeta* function_meta, + const char* name) { + return CassDataType::to(function_meta->get_arg_type(name)); +} + +const CassDataType* cass_function_meta_argument_type_by_name_n(const CassFunctionMeta* function_meta, + const char* name, + size_t name_length) { + return CassDataType::to(function_meta->get_arg_type(cass::StringRef(name, name_length))); +} + +const CassDataType* cass_function_meta_return_type(const CassFunctionMeta* function_meta) { + return CassDataType::to(function_meta->return_type().get()); +} + +void cass_aggregate_meta_name(const CassAggregateMeta* aggregate_meta, + const char** name, + size_t* name_length) { + *name = aggregate_meta->simple_name().data(); + *name_length = aggregate_meta->simple_name().size(); +} + +void cass_aggregate_meta_full_name(const CassAggregateMeta* aggregate_meta, + const char** full_name, + size_t* full_name_length) { + *full_name = aggregate_meta->name().data(); + *full_name_length = aggregate_meta->name().size(); +} + +size_t cass_aggregate_meta_argument_count(const CassAggregateMeta* aggregate_meta) { + return aggregate_meta->arg_types().size(); +} + +const CassDataType* cass_aggregate_meta_argument_type(const CassAggregateMeta* aggregate_meta, + size_t index) { + if (index >= aggregate_meta->arg_types().size()) { + return NULL; + } + return CassDataType::to(aggregate_meta->arg_types()[index].get()); +} + +const CassDataType* cass_aggregate_meta_return_type(const CassAggregateMeta* aggregate_meta) { + return CassDataType::to(aggregate_meta->return_type().get()); +} + +const CassDataType* cass_aggregate_meta_state_type(const CassAggregateMeta* aggregate_meta) { + return CassDataType::to(aggregate_meta->state_type().get()); +} + +const CassFunctionMeta* cass_aggregate_meta_state_func(const CassAggregateMeta* aggregate_meta) { + return CassFunctionMeta::to(aggregate_meta->state_func().get()); +} + +const CassFunctionMeta* cass_aggregate_meta_final_func(const CassAggregateMeta* aggregate_meta) { + return CassFunctionMeta::to(aggregate_meta->final_func().get()); +} + +const CassValue* cass_aggregate_meta_init_cond(const CassAggregateMeta* aggregate_meta) { + return CassValue::to(&aggregate_meta->init_cond()); +} + + +void cass_meta_field_name(const CassMetaField* field, + const char** name, size_t* name_length) { + const std::string& n = field->name(); + *name = n.data(); + *name_length = n.length(); +} + +const CassValue* cass_meta_field_value(const CassMetaField* field) { + return CassValue::to(field->value()); +} + CassIterator* cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta) { return CassIterator::to(schema_meta->iterator_keyspaces()); } @@ -203,6 +382,14 @@ CassIterator* cass_iterator_types_from_keyspace_meta(const CassKeyspaceMeta* key return CassIterator::to(keyspace_meta->iterator_types()); } +CassIterator* cass_iterator_functions_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_functions()); +} + +CassIterator* cass_iterator_aggregates_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_aggregates()); +} + CassIterator* cass_iterator_fields_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { return CassIterator::to(keyspace_meta->iterator_fields()); } @@ -219,6 +406,14 @@ CassIterator* cass_iterator_fields_from_column_meta(const CassColumnMeta* column return CassIterator::to(column_meta->iterator_fields()); } +CassIterator* cass_iterator_fields_from_function_meta(const CassFunctionMeta* function_meta) { + return CassIterator::to(function_meta->iterator_fields()); +} + +CassIterator* cass_iterator_fields_from_aggregate_meta(const CassAggregateMeta* aggregate_meta) { + return CassIterator::to(aggregate_meta->iterator_fields()); +} + const CassKeyspaceMeta* cass_iterator_get_keyspace_meta(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_KEYSPACE_META) { return NULL; @@ -246,6 +441,24 @@ const CassDataType* cass_iterator_get_type_meta(const CassIterator* iterator) { iterator->from())->type()); } +const CassFunctionMeta* cass_iterator_get_function_meta(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_FUNCTION_META) { + return NULL; + } + return CassFunctionMeta::to( + static_cast( + iterator->from())->function()); +} + +const CassAggregateMeta* cass_iterator_get_aggregate_meta(const CassIterator* iterator){ + if (iterator->type() != CASS_ITERATOR_TYPE_AGGREGATE_META) { + return NULL; + } + return CassAggregateMeta::to( + static_cast( + iterator->from())->aggregate()); +} + const CassColumnMeta* cass_iterator_get_column_meta(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_COLUMN_META) { return NULL; @@ -284,13 +497,6 @@ namespace cass { template const T& as_const(const T& x) { return x; } -template -const T* find_by_name(const std::map& map, const std::string& name) { - typename std::map::const_iterator it = map.find(name); - if (it == map.end()) return NULL; - return it->second.get(); -} - const KeyspaceMetadata* Metadata::SchemaSnapshot::get_keyspace(const std::string& name) const { KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(name); if (i == keyspaces_->end()) return NULL; @@ -307,6 +513,21 @@ const UserType* Metadata::SchemaSnapshot::get_type(const std::string& keyspace_n return i->second.get_type(type_name); } +std::string Metadata::full_function_name(StringRef name, const StringRefVec& signature) { + std::string full_name; + bool first = true; + full_name.append(name.begin(), name.end()); + full_name.push_back('('); + for (StringRefVec::const_iterator i = signature.begin(), + end = signature.end(); i != end; ++i) { + if (!first) full_name.push_back(','); + first = false; + full_name.append(i->begin(), i->end()); + } + full_name.push_back(')'); + return full_name; +} + Metadata::SchemaSnapshot Metadata::schema_snapshot() const { ScopedMutex l(&mutex_); return SchemaSnapshot(schema_snapshot_version_, front_.keyspaces()); @@ -351,6 +572,28 @@ void Metadata::update_types(ResultResponse* result) { } } +void Metadata::update_functions(ResultResponse* result) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_functions(result); + } else { + updating_->update_functions(result); + } +} + +void Metadata::update_aggregates(ResultResponse* result) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_aggregates(protocol_version_, result); + } else { + updating_->update_aggregates(protocol_version_, result); + } +} + void Metadata::drop_keyspace(const std::string& keyspace_name) { schema_snapshot_version_++; @@ -384,6 +627,28 @@ void Metadata::drop_type(const std::string& keyspace_name, const std::string& ty } } +void Metadata::drop_function(const std::string& keyspace_name, const std::string& full_function_name) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_function(keyspace_name, full_function_name); + } else { + updating_->drop_function(keyspace_name, full_function_name); + } +} + +void Metadata::drop_aggregate(const std::string& keyspace_name, const std::string& full_aggregate_name) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_aggregate(keyspace_name, full_aggregate_name); + } else { + updating_->drop_aggregate(keyspace_name, full_aggregate_name); + } +} + void Metadata::clear_and_update_back() { token_map_.clear(); back_.clear(); @@ -572,6 +837,34 @@ void KeyspaceMetadata::drop_type(const std::string& type_name) { types_->erase(type_name); } +void KeyspaceMetadata::add_function(const FunctionMetadata::Ptr& function) { + (*functions_)[function->name()] = function; +} + +const FunctionMetadata* KeyspaceMetadata::get_function(const std::string& full_function_name) const { + FunctionMetadata::Map::const_iterator i = functions_->find(full_function_name); + if (i == functions_->end()) return NULL; + return i->second.get(); +} + +void KeyspaceMetadata::drop_function(const std::string& full_function_name) { + functions_->erase(full_function_name); +} + +const AggregateMetadata* KeyspaceMetadata::get_aggregate(const std::string& full_aggregate_name) const { + AggregateMetadata::Map::const_iterator i = aggregates_->find(full_aggregate_name); + if (i == aggregates_->end()) return NULL; + return i->second.get(); +} + +void KeyspaceMetadata::add_aggregate(const AggregateMetadata::Ptr& aggregate) { + (*aggregates_)[aggregate->name()] = aggregate; +} + +void KeyspaceMetadata::drop_aggregate(const std::string& full_aggregate_name) { + aggregates_->erase(full_aggregate_name); +} + TableMetadata::TableMetadata(const std::string& name, int version, const SharedRefPtr& buffer, const Row* row) : MetadataBase(name) { @@ -696,6 +989,127 @@ void TableMetadata::key_aliases(KeyAliases* output) const { } } +FunctionMetadata::FunctionMetadata(const std::string& name, const Value* signature, + const SharedRefPtr& buffer, const Row* row) + : MetadataBase(Metadata::full_function_name(name, signature->as_stringlist())) + , simple_name_(name) { + const Value* value1; + const Value* value2; + + add_field(buffer, row, "keyspace_name"); + add_field(buffer, row, "function_name"); + + value1 = add_field(buffer, row, "argument_names"); + value2 = add_field(buffer, row, "argument_types"); + if (value1 != NULL && + value1->value_type() == CASS_VALUE_TYPE_LIST && + value1->primary_value_type() == CASS_VALUE_TYPE_VARCHAR && + value2 != NULL && + value2->value_type() == CASS_VALUE_TYPE_LIST && + value2->primary_value_type() == CASS_VALUE_TYPE_VARCHAR) { + CollectionIterator iterator1(value1); + CollectionIterator iterator2(value1); + while (iterator1.next() && iterator2.next()) { + StringRef arg_name(iterator1.value()->to_string_ref()); + DataType::Ptr arg_type(TypeParser::parse_one(iterator2.value()->to_string())); + args_.push_back(Argument(arg_name, arg_type)); + args_by_name_[arg_name] = arg_type; + } + } + + value1 = add_field(buffer, row, "return_type"); + if (value1 != NULL && + value1->value_type() == CASS_VALUE_TYPE_VARCHAR) { + return_type_ = TypeParser::parse_one(value1->to_string()); + } + + value1 = add_field(buffer, row, "body"); + if (value1 != NULL && + value1->value_type() == CASS_VALUE_TYPE_VARCHAR) { + body_ = value1->to_string_ref(); + } + + value1 = add_field(buffer, row, "language"); + if (value1 != NULL && + value1->value_type() == CASS_VALUE_TYPE_VARCHAR) { + language_ = value1->to_string_ref(); + } + + value1 = add_field(buffer, row, "called_on_null_input"); + if (value1 != NULL && + value1->value_type() == CASS_VALUE_TYPE_BOOLEAN) { + called_on_null_input_ = value1->as_bool(); + } +} + +const DataType* FunctionMetadata::get_arg_type(StringRef name) const { + Argument::Map::const_iterator i = args_by_name_.find(name); + if (i != args_by_name_.end()) return NULL; + return i->second.get(); +} + +AggregateMetadata::AggregateMetadata(const std::string& name, const Value* signature, + const FunctionMetadata::Map& functions, + int version, const SharedRefPtr& buffer, const Row* row) + : MetadataBase(Metadata::full_function_name(name, signature->as_stringlist())) + , simple_name_(name) { + const Value* value; + + add_field(buffer, row, "keyspace_name"); + add_field(buffer, row, "aggregate_name"); + + value = add_field(buffer, row, "argument_types"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_LIST && + value->primary_value_type() == CASS_VALUE_TYPE_VARCHAR) { + CollectionIterator iterator(value); + while (iterator.next()) { + arg_types_.push_back(TypeParser::parse_one(iterator.value()->to_string())); + } + } + + value = add_field(buffer, row, "return_type"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + return_type_ = TypeParser::parse_one(value->to_string()); + } + + value = add_field(buffer, row, "state_type"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + state_type_ = TypeParser::parse_one(value->to_string()); + } + + value = add_field(buffer, row, "final_func"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + StringRefVec final_func_signature(1, state_type_->to_string()); + std::string full_final_func_name(Metadata::full_function_name(value->to_string(), final_func_signature)); + FunctionMetadata::Map::const_iterator i = functions.find(full_final_func_name); + if (i != functions.end()) final_func_ = i->second; + } + + value = add_field(buffer, row, "state_func"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + StringRefVec state_func_signature; + state_func_signature.push_back(state_type_->to_string()); + CollectionIterator iterator(signature); + while (iterator.next()) { + state_func_signature.push_back(iterator.value()->to_string_ref()); + } + std::string full_state_func_name(Metadata::full_function_name(value->to_string(), state_func_signature)); + FunctionMetadata::Map::const_iterator i = functions.find(full_state_func_name); + if (i != functions.end()) state_func_ = i->second; + } + + value = add_field(buffer, row, "initcond"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_BLOB) { + init_cond_ = Value(version, state_type_, value->data(), value->size()); + } +} + ColumnMetadata::ColumnMetadata(const std::string& name, int version, const SharedRefPtr& buffer, const Row* row) : MetadataBase(name) @@ -855,7 +1269,7 @@ void Metadata::InternalData::update_types(ResultResponse* result) { std::string field_name(name->to_string()); - SharedRefPtr data_type = TypeParser::parse_one(type->to_string()); + SharedRefPtr data_type = TypeParser::parse_one(type->to_string()); if (!data_type) { LOG_ERROR("Invalid 'field_type' for field \"%s\", keyspace \"%s\" and type \"%s\"", field_name.c_str(), @@ -872,6 +1286,57 @@ void Metadata::InternalData::update_types(ResultResponse* result) { } } +void Metadata::InternalData::update_functions(ResultResponse* result) { + SharedRefPtr buffer = result->buffer(); + + result->decode_first_row(); + ResultIterator rows(result); + + while (rows.next()) { + std::string keyspace_name; + std::string function_name; + const Row* row = rows.row(); + + const Value* signature = row->get_by_name("signature"); + if (!row->get_string_by_name("keyspace_name", &keyspace_name) || + !row->get_string_by_name("function_name", &function_name) || + signature == NULL) { + LOG_ERROR("Unable to column value for 'keyspace_name', 'function_name' or 'signature'"); + continue; + } + + get_or_create_keyspace(keyspace_name)->add_function(FunctionMetadata::Ptr(new FunctionMetadata(function_name, + signature, buffer, row))); + + } +} + +void Metadata::InternalData::update_aggregates(int version, ResultResponse* result) { + SharedRefPtr buffer = result->buffer(); + + result->decode_first_row(); + ResultIterator rows(result); + + while (rows.next()) { + std::string keyspace_name; + std::string aggregate_name; + const Row* row = rows.row(); + + const Value* signature = row->get_by_name("signature"); + if (!row->get_string_by_name("keyspace_name", &keyspace_name) || + !row->get_string_by_name("aggregate_name", &aggregate_name) || + signature == NULL) { + LOG_ERROR("Unable to column value for 'keyspace_name', 'aggregate_name' or 'signature'"); + continue; + } + + KeyspaceMetadata* keyspace = get_or_create_keyspace(keyspace_name); + keyspace->add_aggregate(AggregateMetadata::Ptr(new AggregateMetadata(aggregate_name, signature, + keyspace->functions(), + version, buffer, row))); + } +} + void Metadata::InternalData::drop_keyspace(const std::string& keyspace_name) { keyspaces_->erase(keyspace_name); } @@ -888,6 +1353,18 @@ void Metadata::InternalData::drop_type(const std::string& keyspace_name, const s i->second.drop_type(type_name); } +void Metadata::InternalData::drop_function(const std::string& keyspace_name, const std::string& full_function_name) { + KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); + if (i == keyspaces_->end()) return; + i->second.drop_function(full_function_name); +} + +void Metadata::InternalData::drop_aggregate(const std::string& keyspace_name, const std::string& full_aggregate_name) { + KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); + if (i == keyspaces_->end()) return; + i->second.drop_aggregate(full_aggregate_name); +} + void Metadata::InternalData::update_columns(int version, ResultResponse* result) { SharedRefPtr buffer = result->buffer(); diff --git a/src/metadata.hpp b/src/metadata.hpp index ac6455037..0bb989d4e 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -174,6 +174,73 @@ class MetadataIteratorImpl : public Iterator { IteratorImpl impl_; }; +class FunctionMetadata : public MetadataBase, public RefCounted { +public: + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector Vec; + + struct Argument { + typedef std::vector Vec; + typedef std::map Map; + + Argument(const StringRef& name, const DataType::Ptr& type) + : name(name) + , type(type) { } + const StringRef name; + const DataType::Ptr type; + }; + + FunctionMetadata(const std::string& name, const Value* signature, + const SharedRefPtr& buffer, const Row* row); + + StringRef simple_name() const { return simple_name_; } + const Argument::Vec& args() const { return args_; } + const DataType::Ptr& return_type() const { return return_type_; } + StringRef body() const { return body_; } + StringRef language() const { return language_; } + bool called_on_null_input() const { return called_on_null_input_; } + + const DataType* get_arg_type(StringRef name) const; + +private: + StringRef simple_name_; + Argument::Vec args_; + Argument::Map args_by_name_; + DataType::Ptr return_type_; + StringRef body_; + StringRef language_; + bool called_on_null_input_; +}; + +class AggregateMetadata : public MetadataBase, public RefCounted { +public: + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector Vec; + + AggregateMetadata(const std::string& name, const Value* signature, + const FunctionMetadata::Map& functions, + int version, const SharedRefPtr& buffer, const Row* row); + + StringRef simple_name() const { return simple_name_; } + const DataType::Vec arg_types() const { return arg_types_; } + const DataType::Ptr& return_type() const { return return_type_; } + const DataType::Ptr& state_type() const { return state_type_; } + const FunctionMetadata::Ptr& state_func() const { return state_func_; } + const FunctionMetadata::Ptr& final_func() const { return final_func_; } + const Value& init_cond() const { return init_cond_; } + +private: + StringRef simple_name_; + DataType::Vec arg_types_; + DataType::Ptr return_type_; + DataType::Ptr state_type_; + FunctionMetadata::Ptr state_func_; + FunctionMetadata::Ptr final_func_; + Value init_cond_; +}; + class ColumnMetadata : public MetadataBase, public RefCounted { public: typedef SharedRefPtr Ptr; @@ -191,13 +258,13 @@ class ColumnMetadata : public MetadataBase, public RefCounted { CassColumnType type() const { return type_; } int32_t position() const { return position_; } - const SharedRefPtr& data_type() const { return data_type_; } + const SharedRefPtr& data_type() const { return data_type_; } bool is_reversed() const { return is_reversed_; } private: CassColumnType type_; int32_t position_; - SharedRefPtr data_type_; + SharedRefPtr data_type_; bool is_reversed_; private: @@ -267,13 +334,31 @@ class KeyspaceMetadata : public MetadataBase { const UserType* type() const { return impl_.item().get(); } }; + class FunctionIterator : public MetadataIteratorImpl > { + public: + FunctionIterator(const FunctionIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_FUNCTION_META, collection) { } + const FunctionMetadata* function() const { return impl_.item().get(); } + }; + + class AggregateIterator : public MetadataIteratorImpl > { + public: + AggregateIterator(const AggregateIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_AGGREGATE_META, collection) { } + const AggregateMetadata* aggregate() const { return impl_.item().get(); } + }; + KeyspaceMetadata(const std::string& name) : MetadataBase(name) , tables_(new TableMetadata::Map) - , types_(new TypeMap) { } + , types_(new TypeMap) + , functions_(new FunctionMetadata::Map) + , aggregates_(new AggregateMetadata::Map) { } void update(int version, const SharedRefPtr& buffer, const Row* row); + const FunctionMetadata::Map& functions() const { return *functions_; } + Iterator* iterator_tables() const { return new TableIterator(*tables_); } const TableMetadata* get_table(const std::string& table_name) const; const TableMetadata::Ptr& get_or_create_table(const std::string& name); @@ -285,12 +370,24 @@ class KeyspaceMetadata : public MetadataBase { void add_type(const SharedRefPtr& user_type); void drop_type(const std::string& type_name); + Iterator* iterator_functions() const { return new FunctionIterator(*functions_); } + const FunctionMetadata* get_function(const std::string& full_function_name) const; + void add_function(const FunctionMetadata::Ptr& function); + void drop_function(const std::string& full_function_name); + + Iterator* iterator_aggregates() const { return new AggregateIterator(*aggregates_); } + const AggregateMetadata* get_aggregate(const std::string& full_aggregate_name) const; + void add_aggregate(const AggregateMetadata::Ptr& aggregate); + void drop_aggregate(const std::string& full_aggregate_name); + std::string strategy_class() const { return get_string_field("strategy_class"); } const Value* strategy_options() const { return get_field("strategy_options"); } private: CopyOnWritePtr tables_; CopyOnWritePtr types_; + CopyOnWritePtr functions_; + CopyOnWritePtr aggregates_; }; class Metadata { @@ -320,12 +417,13 @@ class Metadata { const std::string& cf_name, std::vector* output) const; - private: uint32_t version_; KeyspaceMetadata::MapPtr keyspaces_; }; + static std::string full_function_name(StringRef name, const StringRefVec& signature); + public: Metadata() : updating_(&front_) @@ -343,10 +441,14 @@ class Metadata { void update_keyspaces(ResultResponse* result); void update_tables(ResultResponse* tables_result, ResultResponse* columns_result); void update_types(ResultResponse* result); + void update_functions(ResultResponse* result); + void update_aggregates(ResultResponse* result); void drop_keyspace(const std::string& keyspace_name); void drop_table(const std::string& keyspace_name, const std::string& table_name); void drop_type(const std::string& keyspace_name, const std::string& type_name); + void drop_function(const std::string& keyspace_name, const std::string& full_function_name); + void drop_aggregate(const std::string& keyspace_name, const std::string& full_aggregate_name); // This clears and allows updates to the back buffer while preserving // the front buffer for snapshots. @@ -381,10 +483,14 @@ class Metadata { void update_keyspaces(int version, ResultResponse* result, KeyspaceMetadata::Map& updates); void update_tables(int version, ResultResponse* tables_result, ResultResponse* columns_result); void update_types(ResultResponse* result); + void update_functions(ResultResponse* result); + void update_aggregates(int version, ResultResponse* result); void drop_keyspace(const std::string& keyspace_name); void drop_table(const std::string& keyspace_name, const std::string& table_name); void drop_type(const std::string& keyspace_name, const std::string& type_name); + void drop_function(const std::string& keyspace_name, const std::string& full_function_name); + void drop_aggregate(const std::string& keyspace_name, const std::string& full_aggregate_name); void clear() { keyspaces_->clear(); } diff --git a/src/result_response.cpp b/src/result_response.cpp index e0856d227..8e6c83268 100644 --- a/src/result_response.cpp +++ b/src/result_response.cpp @@ -152,7 +152,7 @@ class DataTypeDecoder { } SharedRefPtr decode_collection(CassValueType collection_type) { - DataTypeVec types; + DataType::Vec types; types.push_back(decode()); if (collection_type == CASS_VALUE_TYPE_MAP) { types.push_back(decode()); @@ -185,7 +185,7 @@ class DataTypeDecoder { uint16_t n; buffer_ = decode_uint16(buffer_, n); - DataTypeVec types; + DataType::Vec types; for (uint16_t i = 0; i < n; ++i) { types.push_back(decode()); } diff --git a/src/serialization.hpp b/src/serialization.hpp index 34313b1f7..2180ae78a 100644 --- a/src/serialization.hpp +++ b/src/serialization.hpp @@ -279,15 +279,14 @@ inline char* decode_stringlist(char* input, std::list& output) { inline char* decode_stringlist(char* input, StringRefVec& output) { output.clear(); uint16_t len = 0; - char* buffer = decode_uint16(input, len); + char* pos = decode_uint16(input, len); output.reserve(len); for (int i = 0; i < len; i++) { - char* s = NULL; - size_t size = 0; - buffer = decode_string(buffer, &s, size); - output.push_back(StringRef(s, size)); + StringRef s; + pos = decode_string(pos, &s); + output.push_back(s); } - return buffer; + return pos; } typedef std::map > StringMultimap; diff --git a/src/string_ref.hpp b/src/string_ref.hpp index c4cc1f7a0..2e521045e 100644 --- a/src/string_ref.hpp +++ b/src/string_ref.hpp @@ -123,6 +123,10 @@ class StringRef { return !equals(ref); } + bool operator<(const StringRef& ref) const { + return compare(ref) < 0; + } + private: template int compare(const StringRef& ref, IsEqual is_equal) const { diff --git a/src/type_parser.cpp b/src/type_parser.cpp index 5359610fa..79dc81494 100644 --- a/src/type_parser.cpp +++ b/src/type_parser.cpp @@ -151,14 +151,14 @@ bool TypeParser::is_tuple_type(const std::string& type) { return starts_with(type, TUPLE_TYPE); } -SharedRefPtr TypeParser::parse_one(const std::string& type) { +SharedRefPtr TypeParser::parse_one(const std::string& type) { bool frozen = is_frozen(type); std::string class_name; if (is_reversed(type) || frozen) { if (!get_nested_class_name(type, &class_name)) { - return SharedRefPtr(); + return SharedRefPtr(); } } else { class_name = type; @@ -172,32 +172,32 @@ SharedRefPtr TypeParser::parse_one(const std::string& type) { if (starts_with(next, LIST_TYPE)) { TypeParamsVec params; if (!parser.get_type_params(¶ms) || params.empty()) { - return SharedRefPtr(); + return SharedRefPtr(); } - SharedRefPtr element_type(parse_one(params[0])); + SharedRefPtr element_type(parse_one(params[0])); if (!element_type) { - return SharedRefPtr(); + return SharedRefPtr(); } return CollectionType::list(element_type); } else if(starts_with(next, SET_TYPE)) { TypeParamsVec params; if (!parser.get_type_params(¶ms) || params.empty()) { - return SharedRefPtr(); + return SharedRefPtr(); } - SharedRefPtr element_type(parse_one(params[0])); + SharedRefPtr element_type(parse_one(params[0])); if (!element_type) { - return SharedRefPtr(); + return SharedRefPtr(); } return CollectionType::set(element_type); } else if(starts_with(next, MAP_TYPE)) { TypeParamsVec params; if (!parser.get_type_params(¶ms) || params.size() < 2) { - return SharedRefPtr(); + return SharedRefPtr(); } - SharedRefPtr key_type(parse_one(params[0])); - SharedRefPtr value_type(parse_one(params[1])); + SharedRefPtr key_type(parse_one(params[0])); + SharedRefPtr value_type(parse_one(params[1])); if (!key_type || !value_type) { - return SharedRefPtr(); + return SharedRefPtr(); } return CollectionType::map(key_type, value_type); } @@ -212,67 +212,67 @@ SharedRefPtr TypeParser::parse_one(const std::string& type) { std::string keyspace; if (!parser.read_one(&keyspace)) { - return SharedRefPtr(); + return SharedRefPtr(); } parser.skip_blank_and_comma(); std::string hex; if (!parser.read_one(&hex)) { - return SharedRefPtr(); + return SharedRefPtr(); } std::string type_name; if (!from_hex(hex, &type_name)) { LOG_ERROR("Invalid hex string \"%s\" for parameter", hex.c_str()); - return SharedRefPtr(); + return SharedRefPtr(); } if (keyspace.empty() || type_name.empty()) { LOG_ERROR("UDT has no keyspace or type name"); - return SharedRefPtr(); + return SharedRefPtr(); } parser.skip_blank_and_comma(); NameAndTypeParamsVec raw_fields; if (!parser.get_name_and_type_params(&raw_fields)) { - return SharedRefPtr(); + return SharedRefPtr(); } UserType::FieldVec fields; for (NameAndTypeParamsVec::const_iterator i = raw_fields.begin(), end = raw_fields.end(); i != end; ++i) { - SharedRefPtr data_type = parse_one(i->second); + SharedRefPtr data_type = parse_one(i->second); if (!data_type) { - return SharedRefPtr(); + return SharedRefPtr(); } fields.push_back(UserType::Field(i->first, data_type)); } - return SharedRefPtr(new UserType(keyspace, type_name, fields)); + return SharedRefPtr(new UserType(keyspace, type_name, fields)); } if (is_tuple_type(type)) { TypeParamsVec raw_types; if (!parser.get_type_params(&raw_types)) { - return SharedRefPtr(); + return SharedRefPtr(); } - DataTypeVec types; + DataType::Vec types; for (TypeParamsVec::const_iterator i = raw_types.begin(), end = raw_types.end(); i != end; ++i) { - SharedRefPtr data_type = parse_one(*i); + SharedRefPtr data_type = parse_one(*i); if (!data_type) { - return SharedRefPtr(); + return SharedRefPtr(); } types.push_back(data_type); } - return SharedRefPtr(new TupleType(types)); + return SharedRefPtr(new TupleType(types)); } CassValueType t = get_value_type(next); - return t == CASS_VALUE_TYPE_UNKNOWN ? SharedRefPtr(new CustomType(next)) - : SharedRefPtr(new DataType(t)); + return t == CASS_VALUE_TYPE_UNKNOWN ? SharedRefPtr(new CustomType(next)) + : SharedRefPtr(new DataType(t)); } SharedRefPtr TypeParser::parse_with_composite(const std::string& type) { @@ -282,7 +282,7 @@ SharedRefPtr TypeParser::parse_with_composite(const std::string& ty parser.get_next_name(&next); if (!is_composite(next)) { - SharedRefPtr data_type = parse_one(type); + SharedRefPtr data_type = parse_one(type); if (!data_type) { return SharedRefPtr(); } @@ -315,7 +315,7 @@ SharedRefPtr TypeParser::parse_with_composite(const std::string& ty for (NameAndTypeParamsVec::const_iterator i = params.begin(), end = params.end(); i != end; ++i) { - SharedRefPtr data_type = parse_one(i->second); + SharedRefPtr data_type = parse_one(i->second); if (!data_type) { return SharedRefPtr(); } @@ -323,10 +323,10 @@ SharedRefPtr TypeParser::parse_with_composite(const std::string& ty } } - DataTypeVec types; + DataType::Vec types; ParseResult::ReversedVec reversed; for (size_t i = 0; i < count; ++i) { - SharedRefPtr data_type = parse_one(sub_class_names[i]); + SharedRefPtr data_type = parse_one(sub_class_names[i]); if (!data_type) { return SharedRefPtr(); } @@ -408,7 +408,7 @@ bool TypeParser::Parser::get_name_and_type_params(NameAndTypeParamsVec* params) std::string name; if (!from_hex(hex, &name)) { LOG_ERROR("Invalid hex string \"%s\" for parameter", hex.c_str()); - return SharedRefPtr(); + return SharedRefPtr(); } skip_blank(); diff --git a/src/type_parser.hpp b/src/type_parser.hpp index 73ec9c9bb..cec0aac54 100644 --- a/src/type_parser.hpp +++ b/src/type_parser.hpp @@ -31,16 +31,16 @@ namespace cass { class ParseResult : public RefCounted { public: typedef std::vector ReversedVec; - typedef std::map > CollectionMap; + typedef std::map > CollectionMap; - ParseResult(SharedRefPtr type, bool reversed) + ParseResult(SharedRefPtr type, bool reversed) : is_composite_(false) { types_.push_back(type); reversed_.push_back(reversed); } ParseResult(bool is_composite, - const DataTypeVec& types, + const DataType::Vec& types, ReversedVec reversed, CollectionMap collections) : is_composite_(is_composite) @@ -49,13 +49,13 @@ class ParseResult : public RefCounted { , collections_(collections) { } bool is_composite() const { return is_composite_; } - const DataTypeVec& types() const { return types_; } + const DataType::Vec& types() const { return types_; } const ReversedVec& reversed() const { return reversed_; } const CollectionMap& collections() const { return collections_; } private: bool is_composite_; - DataTypeVec types_; + DataType::Vec types_; ReversedVec reversed_; CollectionMap collections_; }; @@ -70,7 +70,7 @@ class TypeParser { static bool is_user_type(const std::string& type); static bool is_tuple_type(const std::string& type); - static SharedRefPtr parse_one(const std::string& type); + static SharedRefPtr parse_one(const std::string& type); static SharedRefPtr parse_with_composite(const std::string& type); private: diff --git a/src/value.cpp b/src/value.cpp index e0c6f7a89..a54c3a3c2 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -16,6 +16,7 @@ #include "value.hpp" +#include "collection_iterator.hpp" #include "data_type.hpp" #include "external_types.hpp" #include "serialization.hpp" @@ -208,6 +209,13 @@ Value::Value(int protocol_version, } } +bool Value::as_bool() const { + assert(value_type() == CASS_VALUE_TYPE_BOOLEAN); + uint8_t value; + decode_byte(data_, value); + return value != 0; +} + int32_t Value::as_int32() const { assert(value_type() == CASS_VALUE_TYPE_INT); int32_t value; @@ -223,4 +231,15 @@ CassUuid Value::as_uuid() const { } +StringRefVec Value::as_stringlist() const { + assert((value_type() == CASS_VALUE_TYPE_LIST || value_type() == CASS_VALUE_TYPE_SET) && + primary_value_type() == CASS_VALUE_TYPE_VARCHAR); + StringRefVec stringlist; + CollectionIterator iterator(this); + while (iterator.next()) { + stringlist.push_back(StringRef(iterator.value()->to_string_ref())); + } + return stringlist; +} + } // namespace cassandra diff --git a/src/value.hpp b/src/value.hpp index 4f67b7b33..be95c5db3 100644 --- a/src/value.hpp +++ b/src/value.hpp @@ -134,8 +134,10 @@ class Value { return to_string_ref().to_string(); } + bool as_bool() const; int32_t as_int32() const; CassUuid as_uuid() const; + StringRefVec as_stringlist() const; private: int protocol_version_; diff --git a/test/unit_tests/src/test_type_parser.cpp b/test/unit_tests/src/test_type_parser.cpp index e2978fa77..6942bd1bb 100644 --- a/test/unit_tests/src/test_type_parser.cpp +++ b/test/unit_tests/src/test_type_parser.cpp @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_SUITE(type_parser) BOOST_AUTO_TEST_CASE(simple) { - cass::SharedRefPtr data_type; + cass::SharedRefPtr data_type; data_type = cass::TypeParser::parse_one("org.apache.cassandra.db.marshal.InetAddressType"); BOOST_CHECK(data_type->value_type() == CASS_VALUE_TYPE_INET); @@ -37,8 +37,8 @@ BOOST_AUTO_TEST_CASE(simple) data_type = cass::TypeParser::parse_one("org.apache.cassandra.db.marshal.ListType(org.apache.cassandra.db.marshal.UTF8Type)"); BOOST_REQUIRE(data_type->value_type() == CASS_VALUE_TYPE_LIST); - cass::SharedRefPtr collection - = static_cast >(data_type); + cass::SharedRefPtr collection + = static_cast >(data_type); BOOST_REQUIRE(collection->types().size() == 1); BOOST_CHECK(collection->types()[0]->value_type() == CASS_VALUE_TYPE_TEXT); } @@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(invalid) BOOST_AUTO_TEST_CASE(udt) { - cass::SharedRefPtr data_type + cass::SharedRefPtr data_type = cass::TypeParser::parse_one("org.apache.cassandra.db.marshal.UserType(" "foo,61646472657373," "737472656574:org.apache.cassandra.db.marshal.UTF8Type," @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(udt) BOOST_AUTO_TEST_CASE(tuple) { - cass::SharedRefPtr data_type + cass::SharedRefPtr data_type = cass::TypeParser::parse_one("org.apache.cassandra.db.marshal.TupleType(" "org.apache.cassandra.db.marshal.Int32Type," "org.apache.cassandra.db.marshal.UTF8Type," @@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE(tuple) BOOST_REQUIRE(data_type->value_type() == CASS_VALUE_TYPE_TUPLE); - cass::SharedRefPtr tuple = static_cast >(data_type); + cass::SharedRefPtr tuple = static_cast >(data_type); BOOST_REQUIRE(tuple->types().size() == 3); @@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(tuple) BOOST_AUTO_TEST_CASE(nested_collections) { - cass::SharedRefPtr data_type + cass::SharedRefPtr data_type = cass::TypeParser::parse_one("org.apache.cassandra.db.marshal.MapType(" "org.apache.cassandra.db.marshal.UTF8Type," "org.apache.cassandra.db.marshal.FrozenType(" @@ -166,8 +166,8 @@ BOOST_AUTO_TEST_CASE(nested_collections) BOOST_REQUIRE(data_type->value_type() == CASS_VALUE_TYPE_MAP); - cass::SharedRefPtr collection - = static_cast >(data_type); + cass::SharedRefPtr collection + = static_cast >(data_type); BOOST_REQUIRE(collection->types().size() == 2); @@ -262,24 +262,24 @@ BOOST_AUTO_TEST_CASE(composite_with_collections) cass::ParseResult::CollectionMap::const_iterator i; i = result->collections().find("ab"); - cass::SharedRefPtr collection; + cass::SharedRefPtr collection; BOOST_REQUIRE(i != result->collections().end()); BOOST_REQUIRE(i->second->value_type() == CASS_VALUE_TYPE_LIST); - collection = static_cast >(i->second); + collection = static_cast >(i->second); BOOST_REQUIRE(collection->types().size() == 1); BOOST_CHECK(collection->types()[0]->value_type() == CASS_VALUE_TYPE_INT); i = result->collections().find("JKLMNO"); BOOST_REQUIRE(i != result->collections().end()); BOOST_CHECK(i->second->value_type() == CASS_VALUE_TYPE_SET); - collection = static_cast >(i->second); + collection = static_cast >(i->second); BOOST_REQUIRE(collection->types().size() == 1); BOOST_CHECK(collection->types()[0]->value_type() == CASS_VALUE_TYPE_TEXT); i = result->collections().find("jklmno"); BOOST_REQUIRE(i != result->collections().end()); BOOST_CHECK(i->second->value_type() == CASS_VALUE_TYPE_MAP); - collection = static_cast >(i->second); + collection = static_cast >(i->second); BOOST_REQUIRE(collection->types().size() == 2); BOOST_CHECK(collection->types()[0]->value_type() == CASS_VALUE_TYPE_TEXT); BOOST_CHECK(collection->types()[1]->value_type() == CASS_VALUE_TYPE_BIGINT); From c6de6fe331f5be5b48b64e8316a02abd5f94ff07 Mon Sep 17 00:00:00 2001 From: Michael Fero Date: Mon, 19 Oct 2015 10:36:01 -0400 Subject: [PATCH 11/13] Removing CassMetaField methods that were re-added during UDF/UDA feature --- include/cassandra.h | 25 ------------------------- src/metadata.cpp | 12 ------------ 2 files changed, 37 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index f0574eb2d..e08c4caeb 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -2259,31 +2259,6 @@ cass_aggregate_meta_final_func(const CassAggregateMeta* aggregate_meta); CASS_EXPORT const CassValue* cass_aggregate_meta_init_cond(const CassAggregateMeta* aggregate_meta); -/** - * Gets the name for a metadata field - * - * @public @memberof CassMetaField - * - * @param[in] field - * @param[out] name The name of the metadata data field - * @param[out] name_length - */ -CASS_EXPORT void -cass_meta_field_name(const CassMetaField* field, - const char** name, - size_t* name_length); - -/** - * Gets the value for a metadata field - * - * @public @memberof CassMetaField - * - * @param[in] field - * @return The value of the metadata data field - */ -CASS_EXPORT const CassValue* -cass_meta_field_value(const CassMetaField* field); - /*********************************************************************************** * * SSL diff --git a/src/metadata.cpp b/src/metadata.cpp index 889f5535d..3e490b16d 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -358,18 +358,6 @@ const CassValue* cass_aggregate_meta_init_cond(const CassAggregateMeta* aggregat return CassValue::to(&aggregate_meta->init_cond()); } - -void cass_meta_field_name(const CassMetaField* field, - const char** name, size_t* name_length) { - const std::string& n = field->name(); - *name = n.data(); - *name_length = n.length(); -} - -const CassValue* cass_meta_field_value(const CassMetaField* field) { - return CassValue::to(field->value()); -} - CassIterator* cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta) { return CassIterator::to(schema_meta->iterator_keyspaces()); } From 49e017ee8c3cbe77b0edb48a1c928dc4118ac2ca Mon Sep 17 00:00:00 2001 From: Michael Fero Date: Mon, 19 Oct 2015 13:44:23 -0400 Subject: [PATCH 12/13] Fixing const assignment error --- src/metadata.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metadata.hpp b/src/metadata.hpp index 0bb989d4e..80c8fe88d 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -187,8 +187,8 @@ class FunctionMetadata : public MetadataBase, public RefCounted Date: Wed, 21 Oct 2015 12:04:37 -0700 Subject: [PATCH 13/13] Updated UDF/UDA function docs, fixed typos and fixed logging --- include/cassandra.h | 8 ++++++-- src/control_connection.cpp | 12 +++++++----- src/control_connection.hpp | 10 ++++++++++ src/metadata.cpp | 4 ++-- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index e08c4caeb..5c3967807 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -1670,7 +1670,8 @@ cass_keyspace_meta_type_by_name_n(const CassKeyspaceMeta* keyspace_meta, * * @param[in] keyspace_meta * @param[in] name - * @param[in] arguments + * @param[in] arguments A comma delimited list of CQL types (e.g "text,int,...") + * describing the function's signature. * * @return The data function for a user defined function. NULL if function does not exist. */ @@ -1708,7 +1709,8 @@ cass_keyspace_meta_function_by_name_n(const CassKeyspaceMeta* keyspace_meta, * * @param[in] keyspace_meta * @param[in] name - * @param[in] arguments + * @param[in] arguments A comma delimited list of CQL types (e.g "text,int,...") + * describing the aggregate's signature. * * @return The data aggregate for a user defined aggregate. NULL if aggregate does not exist. */ @@ -1726,6 +1728,8 @@ cass_keyspace_meta_aggregate_by_name(const CassKeyspaceMeta* keyspace_meta, * @param[in] keyspace_meta * @param[in] name * @param[in] name_length + * @param[in] arguments + * @param[in] argument_length * @return same as cass_keyspace_meta_aggregate_by_name() * * @see cass_keyspace_meta_aggregate_by_name() diff --git a/src/control_connection.cpp b/src/control_connection.cpp index c7dbc8a4b..63fd5735e 100644 --- a/src/control_connection.cpp +++ b/src/control_connection.cpp @@ -736,8 +736,10 @@ void ControlConnection::refresh_function(const StringRef& keyspace_name, query.append(" WHERE keyspace_name=? AND function_name=? AND signature=?"); } - // TODO: Fix this logging statment - LOG_DEBUG("Refreshing function or aggregate %s", query.c_str()); + LOG_DEBUG("Refreshing %s %s in keyspace %s", + is_aggregate ? "aggregate" : "function", + Metadata::full_function_name(function_name, arg_types).c_str(), + std::string(keyspace_name.data(), keyspace_name.length()).c_str()); SharedRefPtr request(new QueryRequest(query, 3)); SharedRefPtr signature(new Collection(CASS_COLLECTION_TYPE_LIST, arg_types.size())); @@ -765,10 +767,10 @@ void ControlConnection::on_refresh_function(ControlConnection* control_connectio Response* response) { ResultResponse* result = static_cast(response); if (result->row_count() == 0) { - // TODO: Fix this error - LOG_ERROR("No row found for keyspace %s and function %s in system schema.", + LOG_ERROR("No row found for keyspace %s and %s %s", data.keyspace.c_str(), - data.function.c_str()); + data.is_aggregate ? "aggregate" : "function", + Metadata::full_function_name(data.function, data.arg_types_as_string_refs()).c_str()); return; } if (data.is_aggregate) { diff --git a/src/control_connection.hpp b/src/control_connection.hpp index 341589aa9..9b8ace859 100644 --- a/src/control_connection.hpp +++ b/src/control_connection.hpp @@ -171,6 +171,16 @@ class ControlConnection : public Connection::Listener { } } + StringRefVec arg_types_as_string_refs() const { + StringRefVec string_refs; + for (StringVec::const_iterator i = arg_types.begin(), + end = arg_types.end(); + i != end; ++i) { + string_refs.push_back(StringRef(*i)); + } + return string_refs; + } + std::string keyspace; std::string function; StringVec arg_types; diff --git a/src/metadata.cpp b/src/metadata.cpp index 3e490b16d..65e15d1ed 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -1289,7 +1289,7 @@ void Metadata::InternalData::update_functions(ResultResponse* result) { if (!row->get_string_by_name("keyspace_name", &keyspace_name) || !row->get_string_by_name("function_name", &function_name) || signature == NULL) { - LOG_ERROR("Unable to column value for 'keyspace_name', 'function_name' or 'signature'"); + LOG_ERROR("Unable to get column value for 'keyspace_name', 'function_name' or 'signature'"); continue; } @@ -1314,7 +1314,7 @@ void Metadata::InternalData::update_aggregates(int version, ResultResponse* resu if (!row->get_string_by_name("keyspace_name", &keyspace_name) || !row->get_string_by_name("aggregate_name", &aggregate_name) || signature == NULL) { - LOG_ERROR("Unable to column value for 'keyspace_name', 'aggregate_name' or 'signature'"); + LOG_ERROR("Unable to get column value for 'keyspace_name', 'aggregate_name' or 'signature'"); continue; }