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/examples/schema_meta/schema_meta.c b/examples/schema_meta/schema_meta.c index 7d7ac83d2..2506e692b 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 CassIterator* iterator, 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 CassIterator* iterator, 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_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); @@ -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(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..6cd0abffc 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_user_type_by_name(keyspace_meta, "address"); + udt_phone = cass_keyspace_meta_user_type_by_name(keyspace_meta, "phone_numbers"); + } if (udt_address != NULL && udt_phone != NULL) { int i; @@ -168,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); @@ -197,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); @@ -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 3504e4be3..5ee900768 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -316,25 +316,32 @@ typedef struct CassUserType_ CassUserType; typedef struct CassSsl_ CassSsl; /** - * @struct CassSchema + * @struct CassSchemaMeta * - * A snapshot of the cluster's schema metadata. + * A snapshot of the schema's metadata. */ -typedef struct CassSchema_ CassSchema; +typedef struct CassSchemaMeta_ CassSchemaMeta; /** - * @struct CassSchemaMeta + * @struct CassKeyspaceMeta * - * Table/Column schema metdata. + * Keyspace metadata */ -typedef struct CassSchemaMeta_ CassSchemaMeta; +typedef struct CassKeyspaceMeta_ CassKeyspaceMeta; + +/** + * @struct CassTableMeta + * + * Table metadata + */ +typedef struct CassTableMeta_ CassTableMeta; /** - * @struct CassSchemaMetaField + * @struct CassColumnMeta * - * Key/Value metadata field for a keyspace, table or column. + * Column metadata */ -typedef struct CassSchemaMetaField_ CassSchemaMetaField; +typedef struct CassColumnMeta_ CassColumnMeta; /** * @struct CassUuidGen @@ -501,18 +508,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_FIELD, + 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") \ @@ -537,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, @@ -1489,8 +1500,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 +1512,8 @@ cass_session_execute_batch(CassSession* session, * * @see cass_schema_free() */ -CASS_EXPORT const CassSchema* -cass_session_get_schema(CassSession* session); +CASS_EXPORT const CassSchemaMeta* +cass_session_get_schema_meta(const CassSession* session); /** * Gets a copy of this session's performance/diagnostic metrics. @@ -1515,203 +1526,403 @@ 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); /*********************************************************************************** * - * 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 metadata for the provided keyspace name. + * Gets the version of the schema metadata snapshot. * - * @public @memberof CassSchema + * @public @memberof CassSchemaMeta * - * @param[in] schema + * @param[in] schema_meta + */ +CASS_EXPORT cass_uint32_t +cass_schema_meta_snapshot_version(const CassSchemaMeta* schema_meta); + +/** + * Gets the keyspace metadata for the provided keyspace name. + * + * @public @memberof CassSchemaMeta + * + * @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_user_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_user_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 metadata field value. 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 CassValue* +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 CassValue* +cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, + size_t name_length); /** - * Gets a metadata field for the provided name. + * Gets the column metadata for the provided column name. * - * @public @memberof CassSchemaMeta + * @public @memberof CassTableMeta * - * @param[in] meta - * @param[in] name The name of a field - * @return A schema metadata field. NULL if the field does not exist. + * @param[in] table_meta + * @param[in] column * - * @see cass_schema_meta_field_value() + * @return The metadata for a column. NULL if column does not exist. */ -CASS_EXPORT const CassSchemaMetaField* -cass_schema_meta_get_field(const CassSchemaMeta* meta, - const char* name); +CASS_EXPORT const CassColumnMeta* +cass_table_meta_column_by_name(const CassTableMeta* table_meta, + const char* column); /** - * Same as cass_schema_meta_get_field(), but with lengths for string + * Same as cass_table_meta_column_by_name(), but with lengths for string * parameters. * - * @public @memberof CassSchema + * @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. * - * @param[in] meta + * @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 CassTableMeta + * + * @param[in] table_meta + * @param[in] name + * @return A metadata field value. NULL if the field does not exist. + */ +CASS_EXPORT const CassValue* +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_schema_meta_get_field() + * @return same as cass_table_meta_field_by_name() * - * @see cass_schema_meta_get_field() + * @see cass_table_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 CassValue* +cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, + const char* name, + size_t name_length); /** - * Gets the name for a schema metadata field + * Gets the name of the column. * - * @public @memberof CassSchemaMetaField + * @public @memberof CassColumnMeta * - * @param[in] field - * @param[out] name The name of the metadata data field + * @param[in] column_meta + * @param[out] name * @param[out] name_length */ CASS_EXPORT void -cass_schema_meta_field_name(const CassSchemaMetaField* field, - const char** name, - size_t* name_length); +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 value for a schema metadata field + * Gets the data type of the column. + * + * @public @memberof CassColumnMeta + * + * @param[in] column_meta + * @return The column's data type. + */ +CASS_EXPORT CassDataType* +cass_column_meta_data_type(const CassColumnMeta* column_meta); + +/** + * Gets a metadata field for the provided name. + * + * @public @memberof CassColumnMeta + * + * @param[in] column_meta + * @param[in] name + * @return A metadata field value. NULL if the field does not exist. + */ +CASS_EXPORT const CassValue* +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 CassColumnMeta * - * @public @memberof CassSchemaMetaField + * @param[in] column_meta + * @param[in] name + * @param[in] name_length + * @return same as cass_column_meta_field_by_name() * - * @param[in] field - * @return The value of the metadata data field + * @see cass_column_meta_field_by_name() */ CASS_EXPORT const CassValue* -cass_schema_meta_field_value(const CassSchemaMetaField* field); +cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, + const char* name, + size_t name_length); /*********************************************************************************** * @@ -5819,52 +6030,115 @@ 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. - * 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 CassSchema + * @public @memberof CassSchemaMeta * - * @param[in] schema + * @param[in] schema_meta * @return A new iterator that must be freed. * - * @see cass_iterator_get_schema_meta() + * @see cass_iterator_get_keyspace_meta() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_from_schema(const CassSchema* schema); +cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_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 tables. * - * @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_table_meta() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_from_schema_meta(const CassSchemaMeta* meta); +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 schema metadata fields. + * 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_field() + * @see cass_iterator_get_user_type() * @see cass_iterator_free() */ CASS_EXPORT CassIterator* -cass_iterator_fields_from_schema_meta(const CassSchemaMeta* meta); +cass_iterator_user_types_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. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_meta_field_name() + * @see cass_iterator_get_meta_field_value() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +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_name() + * @see cass_iterator_get_meta_field_value() + * @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_name() + * @see cass_iterator_get_meta_field_value() + * @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. @@ -5889,7 +6163,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. @@ -5903,7 +6177,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. @@ -5917,7 +6191,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. @@ -5931,7 +6205,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); /** @@ -5946,7 +6220,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. @@ -5962,7 +6236,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); @@ -5978,11 +6252,10 @@ 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 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 +6263,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 +6277,70 @@ 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_user_type(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 name 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 + * @param[out] name + * @param[out] name_length + * @return CASS_OK if successful, otherwise error occurred + */ +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/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 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..f823263f0 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" @@ -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; } @@ -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_user_type(response->keyspace().to_string(), response->target().to_string()); break; } @@ -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->cluster_meta().clear(); + session->metadata().clear_and_update_back(); bool is_initial_connection = (control_connection->state_ == CONTROL_STATE_NEW); @@ -436,13 +436,14 @@ 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_user_types(static_cast(responses[5].get())); } - session->cluster_meta().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,10 +595,10 @@ 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_->cluster_meta().set_partitioner(partitioner); + session_->metadata().set_partitioner(partitioner); } v = row->get_by_name("tokens"); if (v != NULL) { @@ -607,7 +608,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 +638,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 +672,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 +703,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_user_types(result); } bool ControlConnection::handle_query_invalid_response(Response* response) { 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 9803a4d2c..3be460edb 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" @@ -71,9 +71,10 @@ 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::SchemaMetadata, CassSchemaMeta); -EXTERNAL_TYPE(cass::SchemaMetadataField, CassSchemaMetaField); +EXTERNAL_TYPE(cass::Metadata::SchemaSnapshot, CassSchemaMeta); +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 1abb7010e..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->schema.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/iterator.cpp b/src/iterator.cpp index 33150e02e..32018b8cf 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -21,10 +21,18 @@ #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" { +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(); } @@ -58,88 +66,79 @@ 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(CassIterator* iterator, - const char** name, - size_t* name_length) { - if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE) { +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_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(); return CASS_OK; } -const CassValue* cass_iterator_get_user_type_field_value(CassIterator* iterator) { - if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE) { +const CassValue* cass_iterator_get_user_type_field_value(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_USER_TYPE_FIELD) { 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/metadata.cpp b/src/metadata.cpp new file mode 100644 index 000000000..1567ba311 --- /dev/null +++ b/src/metadata.cpp @@ -0,0 +1,937 @@ +/* + 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 "metadata.hpp" + +#include "buffer.hpp" +#include "collection_iterator.hpp" +#include "external_types.hpp" +#include "iterator.hpp" +#include "logger.hpp" +#include "map_iterator.hpp" +#include "result_iterator.hpp" +#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" + +#include + +extern "C" { + +void cass_schema_meta_free(const CassSchemaMeta* schema_meta) { + delete schema_meta->from(); +} + +cass_uint32_t cass_schema_meta_snapshot_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 CassKeyspaceMeta::to(schema_meta->get_keyspace(keyspace)); +} + +const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name_n(const CassSchemaMeta* schema_meta, + const char* keyspace, + size_t keyspace_length) { + return CassKeyspaceMeta::to(schema_meta->get_keyspace(std::string(keyspace, keyspace_length))); +} + +const CassTableMeta* cass_keyspace_meta_table_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* table) { + return CassTableMeta::to(keyspace_meta->get_table(table)); +} + +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_keyspace_meta_user_type_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* type) { + return CassDataType::to(keyspace_meta->get_user_type(type)); +} + +const CassDataType* cass_keyspace_meta_user_type_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* type, + size_t type_length) { + return CassDataType::to(keyspace_meta->get_user_type(std::string(type, type_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 CassValue* cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* name) { + return CassValue::to(keyspace_meta->get_field(name)); +} + +const CassValue* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* name, size_t name_length) { + return CassValue::to(keyspace_meta->get_field(std::string(name, name_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 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 CassValue* cass_table_meta_field_by_name(const CassTableMeta* table_meta, + const char* name) { + return CassValue::to(table_meta->get_field(name)); +} + +const CassValue* cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, + const char* name, size_t 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) { + return table_meta->columns().size(); +} + +const CassColumnMeta* cass_table_meta_column(const CassTableMeta* table_meta, + size_t index) { + if (index >= table_meta->columns().size()) { + return NULL; + } + return CassColumnMeta::to(table_meta->columns()[index].get()); +} + +size_t cass_table_meta_partition_key_count(const CassTableMeta* table_meta) { + return table_meta->partition_key().size(); +} + +const CassColumnMeta* cass_table_meta_partition_key(const CassTableMeta* table_meta, + size_t index) { + if (index >= table_meta->partition_key().size()) { + return NULL; + } + return CassColumnMeta::to(table_meta->partition_key()[index].get()); +} + +size_t cass_table_meta_clustering_key_count(const CassTableMeta* table_meta) { + return table_meta->clustering_key().size(); +} + +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()); +} + +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(); +} + +CassColumnType cass_column_meta_type(const CassColumnMeta* column_meta) { + return column_meta->type(); +} + +CassDataType* cass_column_meta_data_type(const CassColumnMeta* column_meta) { + return CassDataType::to(column_meta->data_type().get()); +} + +cass_bool_t cass_column_meta_is_reversed(const CassColumnMeta* column_meta) { + return column_meta->is_reversed() ? cass_true : cass_false; +} + +const CassValue* +cass_column_meta_field_by_name(const CassColumnMeta* column_meta, + const char* name) { + return CassValue::to(column_meta->get_field(name)); +} + +const CassValue* +cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, + const char* name, size_t name_length) { + return CassValue::to(column_meta->get_field(std::string(name, name_length))); +} + +CassIterator* cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta) { + return CassIterator::to(schema_meta->iterator_keyspaces()); +} + +CassIterator* cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_tables()); +} + +CassIterator* cass_iterator_user_types_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_user_types()); +} + +CassIterator* cass_iterator_fields_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { + return CassIterator::to(keyspace_meta->iterator_fields()); +} + +CassIterator* cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta) { + return CassIterator::to(table_meta->iterator_columns()); +} + +CassIterator* cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta) { + return CassIterator::to(table_meta->iterator_fields()); +} + +CassIterator* cass_iterator_fields_from_column_meta(const CassColumnMeta* column_meta) { + return CassIterator::to(column_meta->iterator_fields()); +} + +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()); +} + +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()); +} + +const CassDataType* cass_iterator_get_user_type(const CassIterator* iterator) { + if (iterator->type() != CASS_ITERATOR_TYPE_TYPE_META) { + return NULL; + } + return CassDataType::to( + static_cast( + iterator->from())->type()); +} + +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()); +} + +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 CassValue::to( + static_cast( + iterator->from())->field()->value()); +} + +} // extern "C" + +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; + return &i->second; +} + +const UserType* Metadata::SchemaSnapshot::get_user_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_user_type(type_name); +} + +Metadata::SchemaSnapshot Metadata::schema_snapshot() const { + ScopedMutex l(&mutex_); + return SchemaSnapshot(schema_snapshot_version_, front_.keyspaces()); +} + +void Metadata::update_keyspaces(ResultResponse* result) { + KeyspaceMetadata::Map updates; + + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_keyspaces(protocol_version_, result, updates); + } else { + updating_->update_keyspaces(protocol_version_, result, updates); + } + + for (KeyspaceMetadata::Map::const_iterator i = updates.begin(); i != updates.end(); ++i) { + token_map_.update_keyspace(i->first, i->second); + } +} + +void Metadata::update_tables(ResultResponse* tables_result, ResultResponse* columns_result) { + schema_snapshot_version_++; + + 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_user_types(ResultResponse* result) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_user_types(result); + } else { + updating_->update_user_types(result); + } +} + +void Metadata::drop_keyspace(const std::string& keyspace_name) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_keyspace(keyspace_name); + } else { + updating_->drop_keyspace(keyspace_name); + } +} + +void Metadata::drop_table(const std::string& keyspace_name, const std::string& table_name) { + schema_snapshot_version_++; + + 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_user_type(const std::string& keyspace_name, const std::string& type_name) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->drop_user_type(keyspace_name, type_name); + } else { + updating_->drop_user_type(keyspace_name, type_name); + } +} + +void Metadata::clear_and_update_back() { + token_map_.clear(); + back_.clear(); + updating_ = &back_; +} + +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() { + { + ScopedMutex l(&mutex_); + schema_snapshot_version_ = 0; + front_.clear(); + } + back_.clear(); + token_map_.clear(); +} + +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.value(); +} + +std::string MetadataBase::get_string_field(const std::string& name) const { + 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) { + const Value* value = row->get_by_name(name); + if (value == NULL) return NULL; + if (value->size() <= 0) { + fields_[name] = MetadataField(name); + } else { + fields_[name] = MetadataField(name, *value, buffer); + } + return value; +} + +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] = MetadataField(name); + return; + } + + int32_t buffer_size = value->size(); + ScopedPtr buf(new char[buffer_size + 1]); + memcpy(buf.get(), value->data(), buffer_size); + buf[buffer_size] = '\0'; + + rapidjson::Document d; + d.ParseInsitu(buf.get()); + + if (d.HasParseError()) { + LOG_ERROR("Unable to parse JSON (array) for column '%s'", name.c_str()); + return; + } + + if (!d.IsArray()) { + LOG_DEBUG("Expected JSON array for column '%s' (probably null or empty)", name.c_str()); + fields_[name] = MetadataField(name); + return; + } + + Collection collection(CollectionType::list(SharedRefPtr(new DataType(CASS_VALUE_TYPE_TEXT))), + d.Size()); + for (rapidjson::Value::ConstValueIterator i = d.Begin(); i != d.End(); ++i) { + collection.append(cass::CassString(i->GetString(), i->GetStringLength())); + } + + size_t encoded_size = collection.get_items_size(version); + SharedRefPtr encoded(RefBuffer::create(encoded_size)); + + collection.encode_items(version, encoded->data()); + + Value list(version, + collection.data_type(), + d.Size(), + encoded->data(), + encoded_size); + fields_[name] = MetadataField(name, list, encoded); +} + +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] = MetadataField(name); + return; + } + + int32_t buffer_size = value->size(); + ScopedPtr buf(new char[buffer_size + 1]); + memcpy(buf.get(), value->data(), buffer_size); + buf[buffer_size] = '\0'; + + rapidjson::Document d; + d.ParseInsitu(buf.get()); + + if (d.HasParseError()) { + LOG_ERROR("Unable to parse JSON (object) for column '%s'", name.c_str()); + return; + } + + if (!d.IsObject()) { + LOG_DEBUG("Expected JSON object for column '%s' (probably null or empty)", name.c_str()); + 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()); + for (rapidjson::Value::ConstMemberIterator i = d.MemberBegin(); i != d.MemberEnd(); ++i) { + collection.append(CassString(i->name.GetString(), i->name.GetStringLength())); + collection.append(CassString(i->value.GetString(), i->value.GetStringLength())); + } + + size_t encoded_size = collection.get_items_size(version); + SharedRefPtr encoded(RefBuffer::create(encoded_size)); + + collection.encode_items(version, encoded->data()); + + Value map(version, + collection.data_type(), + d.MemberCount(), + encoded->data(), + encoded_size); + fields_[name] = MetadataField(name, map, encoded); +} + +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(); +} + +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_user_type(const std::string& name) const { + UserTypeMap::const_iterator i = user_types_->find(name); + if (i == user_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"); + add_field(buffer, row, "strategy_class"); + add_json_map_field(version, row, "strategy_options"); +} + +void KeyspaceMetadata::add_user_type(const SharedRefPtr& user_type) { + (*user_types_)[user_type->type_name()] = user_type; +} + +void KeyspaceMetadata::drop_user_type(const std::string& type_name) { + user_types_->erase(type_name); +} + +TableMetadata::TableMetadata(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"); + + 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, "id"); + add_json_list_field(version, row, "column_aliases"); + add_field(buffer, row, "comment"); + add_field(buffer, row, "compaction_strategy_class"); + add_json_map_field(version, row, "compaction_strategy_options"); + add_field(buffer, row, "comparator"); + add_json_map_field(version, row, "compression_parameters"); + add_field(buffer, row, "default_time_to_live"); + add_field(buffer, row, "default_validator"); + add_field(buffer, row, "dropped_columns"); + add_field(buffer, row, "gc_grace_seconds"); + add_field(buffer, row, "index_interval"); + add_field(buffer, row, "is_dense"); + add_field(buffer, row, "key_alias"); + add_json_list_field(version, row, "key_aliases"); + add_field(buffer, row, "key_validator"); + add_field(buffer, row, "local_read_repair_chance"); + add_field(buffer, row, "max_compaction_threshold"); + add_field(buffer, row, "max_index_interval"); + add_field(buffer, row, "memtable_flush_period_in_ms"); + add_field(buffer, row, "min_compaction_threshold"); + add_field(buffer, row, "min_index_interval"); + add_field(buffer, row, "populate_io_cache_on_flush"); + add_field(buffer, row, "read_repair_chance"); + add_field(buffer, row, "replicate_on_write"); + add_field(buffer, row, "speculative_retry"); + add_field(buffer, row, "subcomparator"); + add_field(buffer, row, "type"); + 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 Value* aliases = get_field("key_aliases"); + if (aliases != NULL) { + output->reserve(aliases->count()); + CollectionIterator itr(aliases); + while (itr.next()) { + output->push_back(itr.value()->to_string()); + } + } + if (output->empty()) {// C* 1.2 tables created via CQL2 or thrift don't have col meta or key aliases + SharedRefPtr key_validator_type = TypeParser::parse_with_composite(get_string_field("key_validator")); + const size_t count = key_validator_type->types().size(); + std::ostringstream ss("key"); + for (size_t i = 0; i < count; ++i) { + if (i > 0) { + ss.seekp(3);// position after "key" + ss << i + 1; + } + output->push_back(ss.str()); + } + } +} + +ColumnMetadata::ColumnMetadata(const std::string& name, + int version, const SharedRefPtr& buffer, const Row* row) + : MetadataBase(name) + , type_(CASS_COLUMN_TYPE_REGULAR) + , position_(-1) + , is_reversed_(false) { + const Value* value; + + add_field(buffer, row, "keyspace_name"); + add_field(buffer, row, "columnfamily_name"); + add_field(buffer, row, "column_name"); + + 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::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 get 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 get 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_user_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 get 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_user_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_user_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_user_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 get 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 new file mode 100644 index 000000000..8a8c03cad --- /dev/null +++ b/src/metadata.hpp @@ -0,0 +1,435 @@ +/* + 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_SCHEMA_METADATA_HPP_INCLUDED__ +#define __CASS_SCHEMA_METADATA_HPP_INCLUDED__ + +#include "copy_on_write_ptr.hpp" +#include "iterator.hpp" +#include "macros.hpp" +#include "ref_counted.hpp" +#include "scoped_lock.hpp" +#include "scoped_ptr.hpp" +#include "token_map.hpp" +#include "type_parser.hpp" + +#include +#include +#include +#include + +namespace cass { + +class Row; +class ResultResponse; + +template +class MapIteratorImpl { +public: + typedef T ItemType; + typedef std::map Collection; + + MapIteratorImpl(const Collection& map) + : next_(map.begin()) + , end_(map.end()) {} + + bool next() { + if (next_ == end_) { + return false; + } + current_ = next_++; + return true; + } + + const T& item() const { + return current_->second; + } + +private: + typename Collection::const_iterator next_; + typename Collection::const_iterator current_; + typename Collection::const_iterator end_; +}; + +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; + + MetadataField() {} + + MetadataField(const std::string& name) + : name_(name) {} + + MetadataField(const std::string& name, + const Value& value, + const SharedRefPtr& buffer) + : name_(name) + , value_(value) + , buffer_(buffer) {} + + const std::string& name() const { + return name_; + } + + const Value* value() const { + return &value_; + } + +private: + std::string name_; + Value value_; + SharedRefPtr buffer_; +}; + +class MetadataFieldIterator : public Iterator { +public: + typedef MapIteratorImpl::Collection Map; + + MetadataFieldIterator(const Map& map) + : Iterator(CASS_ITERATOR_TYPE_META_FIELD) + , impl_(map) {} + + virtual bool next() { return impl_.next(); } + const MetadataField* field() const { return &impl_.item(); } + +private: + MapIteratorImpl impl_; +}; + +class MetadataBase { +public: + MetadataBase(const std::string& name) + : name_(name) { } + + const std::string& name() const { return name_; } + + 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_); } + +protected: + 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); + + MetadataField::Map fields_; + +private: + const std::string name_; +}; + +template +class MetadataIteratorImpl : public Iterator { +public: + typedef typename IteratorImpl::Collection Collection; + + MetadataIteratorImpl(CassIteratorType type, const Collection& colleciton) + : Iterator(type) + , impl_(colleciton) {} + + virtual bool next() { return impl_.next(); } + +protected: + IteratorImpl impl_; +}; + +class ColumnMetadata : public MetadataBase, public RefCounted { +public: + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector Vec; + + ColumnMetadata(const std::string& name) + : MetadataBase(name) + , type_(CASS_COLUMN_TYPE_REGULAR) + , position_(-1) + , is_reversed_(false) { } + + ColumnMetadata(const std::string& name, + 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 MetadataBase, public RefCounted { +public: + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector KeyAliases; + + 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(); } + }; + + TableMetadata(const std::string& name) + : MetadataBase(name) { } + + 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; + +private: + 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 MetadataBase { +public: + typedef std::map Map; + typedef CopyOnWritePtr MapPtr; + typedef std::map > UserTypeMap; + + 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(); } + }; + + 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(); } + }; + + KeyspaceMetadata(const std::string& name) + : MetadataBase(name) + , tables_(new TableMetadata::Map) + , user_types_(new UserTypeMap) { } + + void update(int version, const SharedRefPtr& buffer, const Row* row); + + 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_user_types() const { return new TypeIterator(*user_types_); } + const UserType* get_user_type(const std::string& type_name) const; + void add_user_type(const SharedRefPtr& user_type); + void drop_user_type(const std::string& type_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 user_types_; +}; + +class Metadata { +public: + class KeyspaceIterator : public MetadataIteratorImpl > { + public: + KeyspaceIterator(const KeyspaceIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_KEYSPACE_META, collection) { } + const KeyspaceMetadata* keyspace() const { return &impl_.item(); } + }; + + class SchemaSnapshot { + public: + SchemaSnapshot(uint32_t version, const KeyspaceMetadata::MapPtr& keyspaces) + : version_(version) + , keyspaces_(keyspaces) { } + + uint32_t version() const { return version_; } + + const KeyspaceMetadata* get_keyspace(const std::string& name) const; + Iterator* iterator_keyspaces() const { return new KeyspaceIterator(*keyspaces_); } + + const UserType* get_user_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: + uint32_t version_; + KeyspaceMetadata::MapPtr keyspaces_; + }; + +public: + Metadata() + : updating_(&front_) + , schema_snapshot_version_(0) + , protocol_version_(0) { + uv_mutex_init(&mutex_); + } + + ~Metadata() { + uv_mutex_destroy(&mutex_); + } + + SchemaSnapshot schema_snapshot() const; + + void update_keyspaces(ResultResponse* result); + void update_tables(ResultResponse* tables_result, ResultResponse* columns_result); + void update_user_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_user_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(); } + void remove_host(SharedRefPtr& host) { token_map_.remove_host(host); } + + const TokenMap& token_map() const { return token_map_; } + +private: + 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_user_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_user_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_; + + // 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 d23b35077..4a2f66a43 100644 --- a/src/replication_strategy.cpp +++ b/src/replication_strategy.cpp @@ -18,6 +18,7 @@ #include "logger.hpp" #include "map_iterator.hpp" +#include "metadata.hpp" #include "token_map.hpp" #include "utils.hpp" @@ -45,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 Value* strategy_options) : ReplicationStrategy(strategy_class) { build_dc_replicas(strategy_options, &replication_factors_); } @@ -134,10 +135,10 @@ void NetworkTopologyStrategy::tokens_to_replicas(const TokenHostMap& primary, To } } -void NetworkTopologyStrategy::build_dc_replicas(const SchemaMetadataField* 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(); @@ -155,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 Value* strategy_options) : ReplicationStrategy(strategy_class) , replication_factor_(0) { replication_factor_ = get_replication_factor(strategy_options); @@ -186,9 +187,9 @@ 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 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 9ef9041ce..c3f5888bc 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 Value; + typedef std::vector Token; typedef std::map > TokenHostMap; typedef std::map TokenReplicaMap; @@ -53,7 +55,7 @@ class NetworkTopologyStrategy : public ReplicationStrategy { static const std::string STRATEGY_CLASS; NetworkTopologyStrategy(const std::string& strategy_class, - const SchemaMetadataField* strategy_options); + const Value* strategy_options); virtual ~NetworkTopologyStrategy() {} virtual bool equal(const KeyspaceMetadata& ks_meta); @@ -66,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 Value* strategy_options, DCReplicaCountMap* dc_replicas); DCReplicaCountMap replication_factors_; }; @@ -76,7 +78,7 @@ class SimpleStrategy : public ReplicationStrategy { static const std::string STRATEGY_CLASS; SimpleStrategy(const std::string& strategy_class, - const SchemaMetadataField* strategy_options); + const Value* strategy_options); virtual ~SimpleStrategy() {} virtual bool equal(const KeyspaceMetadata& ks_meta); @@ -89,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 Value* strategy_options); size_t replication_factor_; }; diff --git a/src/request_handler.hpp b/src/request_handler.hpp index 9bd0c0fa2..9c706b701 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 @@ -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) { } + , 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; - Schema schema; + Metadata::SchemaSnapshot schema_metadata; 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/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_]; } diff --git a/src/schema_metadata.cpp b/src/schema_metadata.cpp deleted file mode 100644 index 5d1eb877c..000000000 --- a/src/schema_metadata.cpp +++ /dev/null @@ -1,572 +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 "schema_metadata.hpp" - -#include "buffer.hpp" -#include "collection_iterator.hpp" -#include "external_types.hpp" -#include "iterator.hpp" -#include "logger.hpp" -#include "map_iterator.hpp" -#include "result_iterator.hpp" -#include "row.hpp" -#include "row_iterator.hpp" -#include "value.hpp" - -#include "third_party/rapidjson/rapidjson/document.h" - -#include - -extern "C" { - -void cass_schema_free(const CassSchema* schema) { - delete schema->from(); -} - -const CassSchemaMeta* cass_schema_get_keyspace(const CassSchema* schema, - const char* keyspace) { - return cass_schema_get_keyspace_n(schema, keyspace, strlen(keyspace)); -} - -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))); -} - -CassSchemaMetaType cass_schema_meta_type(const CassSchemaMeta* meta) { - return meta->type(); -} - -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 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_user_type(cass::to_cql_id(keyspace_id), - cass::to_cql_id(type_name_id)); - return CassDataType::to(user_type.get()); -} - -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 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))); -} - -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 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))); -} - -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 CassValue* cass_schema_meta_field_value(const CassSchemaMetaField* field) { - return CassValue::to(field->value()); -} - -CassIterator* cass_iterator_from_schema(const CassSchema* schema) { - return CassIterator::to(schema->iterator()); -} - -CassIterator* cass_iterator_from_schema_meta(const CassSchemaMeta* meta) { - return CassIterator::to(meta->iterator()); -} - -const CassSchemaMeta* cass_iterator_get_schema_meta(CassIterator* iterator) { - if (iterator->type() != CASS_ITERATOR_TYPE_SCHEMA_META) { - return NULL; - } - return CassSchemaMeta::to( - static_cast( - iterator->from())->meta()); -} - -CassIterator* cass_iterator_fields_from_schema_meta(const CassSchemaMeta* meta) { - return CassIterator::to(meta->iterator_fields()); -} - -const CassSchemaMetaField* cass_iterator_get_schema_meta_field(CassIterator* iterator) { - if (iterator->type() != CASS_ITERATOR_TYPE_SCHEMA_META_FIELD) { - return NULL; - } - return CassSchemaMetaField::to( - static_cast( - iterator->from())->field()); -} - -} // extern "C" - -namespace cass { - -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; -} - -const SchemaMetadata* Schema::get(const std::string& name) const { - return find_by_name(*keyspaces_, name); -} - -SharedRefPtr Schema::get_user_type(const std::string& keyspace, - 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(); - } - - return j->second; -} - -Schema::KeyspacePointerMap Schema::update_keyspaces(ResultResponse* result) { - KeyspacePointerMap 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* ks_meta = get_or_create(keyspace_name); - ks_meta->update(protocol_version_, buffer, row); - updates.insert(std::make_pair(keyspace_name, ks_meta)); - } - return updates; -} - -void Schema::update_tables(ResultResponse* table_result, ResultResponse* col_result) { - SharedRefPtr buffer = table_result->buffer(); - - table_result->decode_first_row(); - ResultIterator rows(table_result); - - std::string keyspace_name; - std::string columnfamily_name; - KeyspaceMetadata* keyspace_metadata = NULL; - - 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_metadata = get_or_create(keyspace_name); - } - - keyspace_metadata->get_or_create(columnfamily_name)->update(protocol_version_, buffer, row); - } - update_columns(col_result); -} - -void Schema::update_usertypes(ResultResponse* usertypes_result) { - - usertypes_result->decode_first_row(); - ResultIterator rows(usertypes_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)); - } - - (*user_types_)[keyspace_name][type_name] - = SharedRefPtr(new UserType(keyspace_name, type_name, fields)); - } -} - -void Schema::update_columns(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* table_metadata = NULL; - std::set cleared_tables; - 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) { - 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_metadata->get_or_create(column_name)->update(protocol_version_, buffer, row); - } -} - -void Schema::drop_keyspace(const std::string& keyspace_name) { - 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 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 Schema::clear() { - keyspaces_->clear(); -} - -const SchemaMetadataField* SchemaMetadata::get_field(const std::string& name) const { - return find_by_name(fields_, name); -} - -std::string SchemaMetadata::get_string_field(const std::string& name) const { - const SchemaMetadataField* 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* value = row->get_by_name(name); - if (value == NULL) return; - if (value->size() <= 0) { - fields_[name] = SchemaMetadataField(name); - return; - } - fields_[name] = SchemaMetadataField(name, *value, buffer); -} - -void SchemaMetadata::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); - return; - } - - int32_t buffer_size = value->size(); - ScopedPtr buf(new char[buffer_size + 1]); - memcpy(buf.get(), value->data(), buffer_size); - buf[buffer_size] = '\0'; - - rapidjson::Document d; - d.ParseInsitu(buf.get()); - - if (d.HasParseError()) { - LOG_ERROR("Unable to parse JSON (array) for column '%s'", name.c_str()); - return; - } - - if (!d.IsArray()) { - LOG_DEBUG("Expected JSON array for column '%s' (probably null or empty)", name.c_str()); - fields_[name] = SchemaMetadataField(name); - return; - } - - Collection collection(CollectionType::list(SharedRefPtr(new DataType(CASS_VALUE_TYPE_TEXT))), - d.Size()); - for (rapidjson::Value::ConstValueIterator i = d.Begin(); i != d.End(); ++i) { - collection.append(cass::CassString(i->GetString(), i->GetStringLength())); - } - - size_t encoded_size = collection.get_items_size(version); - SharedRefPtr encoded(RefBuffer::create(encoded_size)); - - collection.encode_items(version, encoded->data()); - - Value list(version, - collection.data_type(), - d.Size(), - encoded->data(), - encoded_size); - fields_[name] = SchemaMetadataField(name, list, encoded); -} - -void SchemaMetadata::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); - return; - } - - int32_t buffer_size = value->size(); - ScopedPtr buf(new char[buffer_size + 1]); - memcpy(buf.get(), value->data(), buffer_size); - buf[buffer_size] = '\0'; - - rapidjson::Document d; - d.ParseInsitu(buf.get()); - - if (d.HasParseError()) { - LOG_ERROR("Unable to parse JSON (object) for column '%s'", name.c_str()); - return; - } - - if (!d.IsObject()) { - LOG_DEBUG("Expected JSON object for column '%s' (probably null or empty)", name.c_str()); - fields_[name] = SchemaMetadataField(name); - return; - } - - - - Collection collection(CollectionType::map(SharedRefPtr(new DataType(CASS_VALUE_TYPE_TEXT)), - SharedRefPtr(new DataType(CASS_VALUE_TYPE_TEXT))), - 2 * d.MemberCount()); - for (rapidjson::Value::ConstMemberIterator i = d.MemberBegin(); i != d.MemberEnd(); ++i) { - collection.append(CassString(i->name.GetString(), i->name.GetStringLength())); - collection.append(CassString(i->value.GetString(), i->value.GetStringLength())); - } - - size_t encoded_size = collection.get_items_size(version); - SharedRefPtr encoded(RefBuffer::create(encoded_size)); - - collection.encode_items(version, encoded->data()); - - Value map(version, - collection.data_type(), - d.MemberCount(), - encoded->data(), - encoded_size); - fields_[name] = SchemaMetadataField(name, map, encoded); -} - -const SchemaMetadata* KeyspaceMetadata::get_entry(const std::string& name) const { - return find_by_name(tables_, name); -} - -void KeyspaceMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { - add_field(buffer, row, "keyspace_name"); - add_field(buffer, row, "durable_writes"); - add_field(buffer, row, "strategy_class"); - add_json_map_field(version, row, "strategy_options"); -} - -void KeyspaceMetadata::drop_table(const std::string& table_name) { - tables_.erase(table_name); -} - -const SchemaMetadata* TableMetadata::get_entry(const std::string& name) const { - return find_by_name(columns_, name); -} - -void TableMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { - add_field(buffer, row, "keyspace_name"); - add_field(buffer, row, "columnfamily_name"); - add_field(buffer, row, "bloom_filter_fp_chance"); - add_field(buffer, row, "caching"); - add_field(buffer, row, "cf_id"); - add_json_list_field(version, row, "column_aliases"); - add_field(buffer, row, "comment"); - add_field(buffer, row, "compaction_strategy_class"); - add_json_map_field(version, row, "compaction_strategy_options"); - add_field(buffer, row, "comparator"); - add_json_map_field(version, row, "compression_parameters"); - add_field(buffer, row, "default_time_to_live"); - add_field(buffer, row, "default_validator"); - 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"); - add_field(buffer, row, "key_validator"); - add_field(buffer, row, "local_read_repair_chance"); - add_field(buffer, row, "max_compaction_threshold"); - add_field(buffer, row, "max_index_interval"); - add_field(buffer, row, "memtable_flush_period_in_ms"); - add_field(buffer, row, "min_compaction_threshold"); - add_field(buffer, row, "min_index_interval"); - add_field(buffer, row, "populate_io_cache_on_flush"); - add_field(buffer, row, "read_repair_chance"); - add_field(buffer, row, "replicate_on_write"); - add_field(buffer, row, "speculative_retry"); - add_field(buffer, row, "subcomparator"); - add_field(buffer, row, "type"); - add_field(buffer, row, "value_alias"); -} - -void TableMetadata::key_aliases(KeyAliases* output) const { - const SchemaMetadataField* aliases = get_field("key_aliases"); - if (aliases != NULL) { - output->reserve(aliases->value()->count()); - CollectionIterator itr(aliases->value()); - while (itr.next()) { - output->push_back(itr.value()->to_string()); - } - } - if (output->empty()) {// C* 1.2 tables created via CQL2 or thrift don't have col meta or key aliases - SharedRefPtr key_validator_type = TypeParser::parse_with_composite(get_string_field("key_validator")); - const size_t count = key_validator_type->types().size(); - std::ostringstream ss("key"); - for (size_t i = 0; i < count; ++i) { - if (i > 0) { - ss.seekp(3);// position after "key" - ss << i + 1; - } - output->push_back(ss.str()); - } - } -} - -void ColumnMetadata::update(int version, const SharedRefPtr& buffer, const Row* row) { - 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"); - add_field(buffer, row, "index_name"); - add_json_map_field(version, row, "index_options"); - 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); - 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); - } - } -} - -} // namespace cass - diff --git a/src/schema_metadata.hpp b/src/schema_metadata.hpp deleted file mode 100644 index d8bb4f576..000000000 --- a/src/schema_metadata.hpp +++ /dev/null @@ -1,266 +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_SCHEMA_METADATA_HPP_INCLUDED__ -#define __CASS_SCHEMA_METADATA_HPP_INCLUDED__ - -#include "copy_on_write_ptr.hpp" -#include "iterator.hpp" -#include "scoped_lock.hpp" -#include "scoped_ptr.hpp" -#include "type_parser.hpp" - -#include -#include -#include -#include - -namespace cass { - -class Row; -class ResultResponse; - -template -class SchemaMapIteratorImpl { -public: - typedef std::map Map; - - SchemaMapIteratorImpl(const Map& map) - : next_(map.begin()) - , end_(map.end()) {} - - bool next() { - if (next_ == end_) { - return false; - } - current_ = next_++; - return true; - } - - const T* item() const { - return ¤t_->second; - } - -private: - typename Map::const_iterator next_; - typename Map::const_iterator current_; - typename Map::const_iterator end_; -}; - -class SchemaMetadataField { -public: - typedef std::map Map; - - SchemaMetadataField() {} - - SchemaMetadataField(const std::string& name) - : name_(name) {} - - SchemaMetadataField(const std::string& name, - const Value& value, - const SharedRefPtr& buffer) - : name_(name) - , value_(value) - , buffer_(buffer) {} - - const std::string& name() const { - return name_; - } - - const Value* value() const { - return &value_; - } - -private: - std::string name_; - Value value_; - SharedRefPtr buffer_; -}; - -class SchemaMetadataFieldIterator : public Iterator { -public: - typedef SchemaMapIteratorImpl Map; - - SchemaMetadataFieldIterator(const Map& map) - : Iterator(CASS_ITERATOR_TYPE_SCHEMA_META_FIELD) - , impl_(map) {} - - virtual bool next() { return impl_.next(); } - const SchemaMetadataField* field() const { return impl_.item(); } - -private: - SchemaMapIteratorImpl impl_; -}; - -class SchemaMetadata { -public: - SchemaMetadata(CassSchemaMetaType type) - : type_(type) {} - - virtual ~SchemaMetadata() {} - - 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; - std::string get_string_field(const std::string& name) const; - Iterator* iterator_fields() const { return new SchemaMetadataFieldIterator(fields_); } - -protected: - void 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_; - -private: - const CassSchemaMetaType type_; -}; - -class SchemaMetadataIterator : public Iterator { -public: - SchemaMetadataIterator() - : Iterator(CASS_ITERATOR_TYPE_SCHEMA_META) {} - virtual const SchemaMetadata* meta() const = 0; -}; - -template -class SchemaMetadataIteratorImpl : public SchemaMetadataIterator { -public: - typedef typename SchemaMapIteratorImpl::Map Map; - - SchemaMetadataIteratorImpl(const Map& map) - : impl_(map) {} - - virtual bool next() { return impl_.next(); } - virtual const SchemaMetadata* meta() const { return impl_.item(); } - -private: - SchemaMapIteratorImpl impl_; -}; - -class ColumnMetadata : public SchemaMetadata { -public: - typedef std::map Map; - - ColumnMetadata() - : SchemaMetadata(CASS_SCHEMA_META_TYPE_COLUMN) {} - - virtual const SchemaMetadata* get_entry(const std::string& name) const { - return NULL; - } - virtual Iterator* iterator() const { return NULL; } - - void update(int version, const SharedRefPtr& buffer, const Row* row); -}; - -class TableMetadata : public SchemaMetadata { -public: - typedef std::map Map; - typedef SchemaMetadataIteratorImpl ColumnIterator; - typedef std::vector KeyAliases; - - TableMetadata() - : SchemaMetadata(CASS_SCHEMA_META_TYPE_TABLE) {} - - virtual const SchemaMetadata* get_entry(const std::string& name) const; - virtual Iterator* iterator() const { return new ColumnIterator(columns_); } - - ColumnMetadata* get_or_create(const std::string& name) { return &columns_[name]; } - void update(int version, const SharedRefPtr& buffer, const Row* row); - - void key_aliases(KeyAliases* output) const; - void clear_columns() { columns_.clear(); } - -private: - ColumnMetadata::Map columns_; -}; - -class KeyspaceMetadata : public SchemaMetadata { -public: - typedef std::map Map; - typedef SchemaMetadataIteratorImpl TableIterator; - - KeyspaceMetadata() - : SchemaMetadata(CASS_SCHEMA_META_TYPE_KEYSPACE) {} - - 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]; } - void update(int version, const SharedRefPtr& buffer, const Row* row); - void drop_table(const std::string& table_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_; -}; - -class Schema { -public: - typedef SchemaMetadataIteratorImpl KeyspaceIterator; - typedef std::map KeyspacePointerMap; - typedef std::map > UserTypeMap; - typedef std::map KeyspaceUserTypeMap; - - Schema() - : keyspaces_(new KeyspaceMetadata::Map) - , user_types_(new KeyspaceUserTypeMap) - , protocol_version_(0) {} - - void set_protocol_version(int version) { - protocol_version_ = version; - } - - const SchemaMetadata* get(const std::string& name) const; - Iterator* iterator() const { return new KeyspaceIterator(*keyspaces_); } - - 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; - -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_; - - // Only used internally on a single thread, there's - // no need for copy-on-write. - int protocol_version_; -}; - -} // namespace cass - -#endif diff --git a/src/session.cpp b/src/session.cpp index 33ef5c1db..618128830 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 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(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..296d384f9 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" @@ -25,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" @@ -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..f20783f64 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 { @@ -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))); - } - - 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_user_type(keyspace, udt_name); + if (schema_meta) { + const cass::UserType* udt = schema_meta->get_user_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/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 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/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..5041a11bd 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_snapshot_version(schema_meta_) == cass_schema_meta_snapshot_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_snapshot_version(schema_meta_) == cass_schema_meta_snapshot_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,38 @@ 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()); CassString name; - cass_schema_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)); - // 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 +204,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 +293,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_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_schema_meta_field_value(cass_schema_meta_get_field(table_meta, "comment")), COMMENT); + verify_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_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 +322,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_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_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 +374,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_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")); } @@ -382,7 +395,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 +426,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 +451,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 +508,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 +517,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 +530,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 +539,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..b76bc29c8 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_user_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_user_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)); } @@ -123,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())); @@ -148,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())); @@ -176,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())); @@ -208,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())); @@ -343,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()); @@ -477,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); @@ -492,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); 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..5dd187975 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); } +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; +}; + +BOOST_AUTO_TEST_CASE(nested) +{ + 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()