/* ********************************************************************************************** * File: maat_table.c * Description: * Authors: Liu WenTan * Date: 2022-10-31 * Copyright: (c) Since 2022 Geedge Networks, Ltd. All rights reserved. *********************************************************************************************** */ #include #include #include "log/log.h" #include "maat_utils.h" #include "maat_table.h" #include "maat_rule.h" #include "maat_kv.h" #include "maat_expr.h" #include "maat_ip.h" #include "maat_compile.h" #include "maat_group.h" #include "maat_flag.h" #include "maat_plugin.h" #include "maat_ip_plugin.h" #include "maat_bool_plugin.h" #include "maat_fqdn_plugin.h" #include "maat_interval.h" #include "maat_virtual.h" #define MODULE_TABLE module_name_str("maat.table") struct maat_table { int table_id; char table_name[NAME_MAX]; enum table_type table_type; int valid_column; void *schema; void *runtime; void *updating_runtime; }; struct table_manager { struct maat_table *tbl[MAX_TABLE_NUM]; size_t n_table; struct rule_tag *accept_tags; size_t n_accept_tag; int default_compile_table_id; int g2g_table_id; struct maat_kv_store *tablename2id_map; struct maat_garbage_bin *ref_garbage_bin; struct log_handle *logger; }; struct table_operations { enum table_type type; void *(*new_schema)(cJSON *json, struct table_manager *tbl_mgr, const char *table_name, struct log_handle *logger); void (*free_schema)(void *schema); void *(*new_runtime)(void *schema, size_t max_thread_num, struct maat_garbage_bin *garbage_bin, struct log_handle *logger); void (*free_runtime)(void *runtime); int (*update_runtime)(void *runtime, void *schema, const char *table_name, const char *line, int valid_column); int (*commit_runtime)(void *runtime, const char *table_name, long long maat_rt_version); long long (*rule_count)(void *runtime); long long (*scan_count)(void *runtime); long long (*scan_cpu_time)(void *runtime); long long (*hit_count)(void *runtime); long long (*update_err_count)(void *runtime); }; struct table_operations table_ops[TABLE_TYPE_MAX] = { { .type = TABLE_TYPE_FLAG, .new_schema = flag_schema_new, .free_schema = flag_schema_free, .new_runtime = flag_runtime_new, .free_runtime = flag_runtime_free, .update_runtime = flag_runtime_update, .commit_runtime = flag_runtime_commit, .rule_count = flag_runtime_rule_count, .scan_count = flag_runtime_scan_count, .scan_cpu_time = flag_runtime_scan_cpu_time, .hit_count = flag_runtime_hit_count, .update_err_count = flag_runtime_update_err_count }, { .type = TABLE_TYPE_FLAG_PLUS, .new_schema = flag_schema_new, .free_schema = flag_schema_free, .new_runtime = flag_runtime_new, .free_runtime = flag_runtime_free, .update_runtime = flag_runtime_update, .commit_runtime = flag_runtime_commit, .rule_count = flag_runtime_rule_count, .scan_count = flag_runtime_scan_count, .scan_cpu_time = flag_runtime_scan_cpu_time, .hit_count = flag_runtime_hit_count, .update_err_count = flag_runtime_update_err_count }, { .type = TABLE_TYPE_EXPR, .new_schema = expr_schema_new, .free_schema = expr_schema_free, .new_runtime = expr_runtime_new, .free_runtime = expr_runtime_free, .update_runtime = expr_runtime_update, .commit_runtime = expr_runtime_commit, .rule_count = expr_runtime_rule_count, .scan_count = expr_runtime_scan_count, .scan_cpu_time = expr_runtime_scan_cpu_time, .hit_count = expr_runtime_hit_count, .update_err_count = expr_runtime_update_err_count }, { .type = TABLE_TYPE_EXPR_PLUS, .new_schema = expr_schema_new, .free_schema = expr_schema_free, .new_runtime = expr_runtime_new, .free_runtime = expr_runtime_free, .update_runtime = expr_runtime_update, .commit_runtime = expr_runtime_commit, .rule_count = expr_runtime_rule_count, .scan_count = expr_runtime_scan_count, .scan_cpu_time = expr_runtime_scan_cpu_time, .hit_count = expr_runtime_hit_count, .update_err_count = expr_runtime_update_err_count }, { .type = TABLE_TYPE_IP_PLUS, .new_schema = ip_schema_new, .free_schema = ip_schema_free, .new_runtime = ip_runtime_new, .free_runtime = ip_runtime_free, .update_runtime = ip_runtime_update, .commit_runtime = ip_runtime_commit, .rule_count = ip_runtime_rule_count, .scan_count = ip_runtime_scan_count, .scan_cpu_time = ip_runtime_scan_cpu_time, .hit_count = ip_runtime_hit_count, .update_err_count = ip_runtime_update_err_count }, { .type = TABLE_TYPE_INTERVAL, .new_schema = interval_schema_new, .free_schema = interval_schema_free, .new_runtime = interval_runtime_new, .free_runtime = interval_runtime_free, .update_runtime = interval_runtime_update, .commit_runtime = interval_runtime_commit, .rule_count = interval_runtime_rule_count, .scan_count = interval_runtime_scan_count, .scan_cpu_time = interval_runtime_scan_cpu_time, .hit_count = interval_runtime_hit_count, .update_err_count = interval_runtime_update_err_cnt }, { .type = TABLE_TYPE_INTERVAL_PLUS, .new_schema = interval_schema_new, .free_schema = interval_schema_free, .new_runtime = interval_runtime_new, .free_runtime = interval_runtime_free, .update_runtime = interval_runtime_update, .commit_runtime = interval_runtime_commit, .rule_count = interval_runtime_rule_count, .scan_count = interval_runtime_scan_count, .scan_cpu_time = interval_runtime_scan_cpu_time, .hit_count = interval_runtime_hit_count, .update_err_count = interval_runtime_update_err_cnt }, { .type = TABLE_TYPE_PLUGIN, .new_schema = plugin_schema_new, .free_schema = plugin_schema_free, .new_runtime = plugin_runtime_new, .free_runtime = plugin_runtime_free, .update_runtime = plugin_runtime_update, .commit_runtime = plugin_runtime_commit, .rule_count = plugin_runtime_rule_count, .update_err_count = plugin_runtime_update_err_count }, { .type = TABLE_TYPE_IP_PLUGIN, .new_schema = ip_plugin_schema_new, .free_schema = ip_plugin_schema_free, .new_runtime = ip_plugin_runtime_new, .free_runtime = ip_plugin_runtime_free, .update_runtime = ip_plugin_runtime_update, .commit_runtime = ip_plugin_runtime_commit, .rule_count = ip_plugin_runtime_rule_count, .scan_count = ip_plugin_runtime_scan_count, .scan_cpu_time = ip_plugin_runtime_scan_cpu_time, .update_err_count = ip_plugin_runtime_update_err_count }, { .type = TABLE_TYPE_FQDN_PLUGIN, .new_schema = fqdn_plugin_schema_new, .free_schema = fqdn_plugin_schema_free, .new_runtime = fqdn_plugin_runtime_new, .free_runtime = fqdn_plugin_runtime_free, .update_runtime = fqdn_plugin_runtime_update, .commit_runtime = fqdn_plugin_runtime_commit, .rule_count = fqdn_plugin_runtime_rule_count, .scan_count = fqdn_plugin_runtime_scan_count, .scan_cpu_time = fqdn_plugin_runtime_scan_cpu_time, .update_err_count = fqdn_plugin_runtime_update_err_count }, { .type = TABLE_TYPE_BOOL_PLUGIN, .new_schema = bool_plugin_schema_new, .free_schema = bool_plugin_schema_free, .new_runtime = bool_plugin_runtime_new, .free_runtime = bool_plugin_runtime_free, .update_runtime = bool_plugin_runtime_update, .commit_runtime = bool_plugin_runtime_commit, .rule_count = bool_plugin_runtime_rule_count, .scan_count = bool_plugin_runtime_scan_count, .scan_cpu_time = bool_plugin_runtime_scan_cpu_time, .update_err_count = bool_plugin_runtime_update_err_count }, { .type = TABLE_TYPE_VIRTUAL, .new_schema = virtual_schema_new, .free_schema = virtual_schema_free, .new_runtime = NULL, .free_runtime = NULL, .update_runtime = NULL, .commit_runtime = NULL }, { .type = TABLE_TYPE_COMPILE, .new_schema = compile_schema_new, .free_schema = compile_schema_free, .new_runtime = compile_runtime_new, .free_runtime = compile_runtime_free, .update_runtime = compile_runtime_update, .commit_runtime = compile_runtime_commit, .rule_count = compile_runtime_rule_count, .update_err_count = compile_runtime_update_err_count }, { .type = TABLE_TYPE_GROUP2GROUP, .new_schema = group2group_schema_new, .free_schema = group2group_schema_free, .new_runtime = group2group_runtime_new, .free_runtime = group2group_runtime_free, .update_runtime = group2group_runtime_update, .commit_runtime = group2group_runtime_commit, .rule_count = group2group_runtime_rule_count, .update_err_count = group2group_runtime_update_err_count }, { .type = TABLE_TYPE_GROUP2COMPILE, .new_schema = group2compile_schema_new, .free_schema = group2compile_schema_free, .new_runtime = group2compile_runtime_new, .free_runtime = group2compile_runtime_free, .update_runtime = group2compile_runtime_update, .commit_runtime = NULL, .rule_count = group2compile_runtime_rule_count, .update_err_count = group2compile_runtime_update_err_count } }; //@param value is a JSON, like {"tags":[{"tag":"location","value":"北京/朝阳/华严北里/甲22号},{"tag":"isp","value":"电信"}]} size_t parse_accept_tag(const char *value, struct rule_tag **result, struct log_handle *logger) { if (NULL == value || NULL == result || NULL == logger) { return 0; } cJSON *json = cJSON_Parse(value); if (!json) { log_error(logger, MODULE_TABLE, "[%s:%d] parse accept tag Error before: %-200.200s", __FUNCTION__, __LINE__, cJSON_GetErrorPtr()); return 0; } cJSON *tag = NULL, *tmp = NULL; cJSON *array = cJSON_GetObjectItem(json, "tags"); int n_tag = cJSON_GetArraySize(array); struct rule_tag *p = ALLOC(struct rule_tag, n_tag); for (int i = 0; i < n_tag; i++) { tag = cJSON_GetArrayItem(array, i); tmp = cJSON_GetObjectItem(tag, "tag"); p[i].tag_name = maat_strdup(tmp->valuestring); tmp = cJSON_GetObjectItem(tag, "value"); p[i].tag_val = maat_strdup(tmp->valuestring); } cJSON_Delete(json); *result = p; return n_tag; } static int compare_each_tag(cJSON *tag_obj, const struct rule_tag *accept_tags, size_t n_accept_tag) { if (NULL == tag_obj || NULL == accept_tags) { return TAG_MATCH_ERR; } cJSON *tab_name_obj = cJSON_GetObjectItem(tag_obj, "tag"); if (NULL == tab_name_obj || tab_name_obj->type != cJSON_String) { return TAG_MATCH_ERR; } const char *tag_name = tab_name_obj->valuestring; cJSON *tag_vals_array = cJSON_GetObjectItem(tag_obj, "value"); if (NULL == tag_vals_array || tag_vals_array->type != cJSON_Array) { return TAG_MATCH_ERR; } int name_matched = 0; int n_val = cJSON_GetArraySize(tag_vals_array); for (size_t i = 0; i < n_accept_tag; i++) { if (0 != strcmp(accept_tags[i].tag_name, tag_name)) { continue; } name_matched++; for (int j = 0; j < n_val; j++) { cJSON *tag_val_obj = cJSON_GetArrayItem(tag_vals_array, j); if (NULL == tag_val_obj || tag_val_obj->type != cJSON_String) { return TAG_MATCH_ERR; } const char *tag_val = tag_val_obj->valuestring; // compare a/b/c with a/b/c/d is a miss. if (strlen(accept_tags[i].tag_val) < strlen(tag_val)) { continue; } // compare a1a2/b1/c1 with a1a2/b/ is a miss. //make sure the overlap is ended with a '/' if (0 == strncmp(accept_tags[i].tag_val, tag_val, strlen(tag_val)) && (strlen(accept_tags[i].tag_val) == strlen(tag_val) || accept_tags[i].tag_val[strlen(tag_val)] == '/')) { return TAG_MATCH_MATCHED; } } } //no matched name is considered as a if (name_matched > 0) { return TAG_MATCH_UNMATCHED; } else { return TAG_MATCH_MATCHED; } } //@param tag_set likes [{"tag":"location","value":["北京/朝阳/华严北里","上海/浦东/陆家嘴"]},{"tag":"isp","value":["电信","移动"]}] static int compare_each_tag_set(cJSON *tag_set, const struct rule_tag *accept_tags, size_t n_accept_tag) { int matched = 0; int n_tag = cJSON_GetArraySize(tag_set); for (int i = 0; i < n_tag; i++) { cJSON *tag_obj = cJSON_GetArrayItem(tag_set, i); if (NULL == tag_obj || tag_obj->type != cJSON_Object) { return TAG_MATCH_ERR; } int ret = compare_each_tag(tag_obj, accept_tags, n_accept_tag); if (ret < 0) { return TAG_MATCH_ERR; } if(1 == ret) { matched++; } } if (matched == n_tag) { return TAG_MATCH_MATCHED; } else { return TAG_MATCH_UNMATCHED; } } //@param value {"tag_sets":[[{"tag":"location","value":["北京/朝阳/华严北里","上海/浦东/陆家嘴"]},{"tag":"isp","value":["电信","移动"]}],[{"tag":"location","value":["北京"]},{"tag":"isp","value":["联通"]}]]} //@return 1 on match, 0 on not match, -1 on error. static int compare_accept_tag(const char *value, const struct rule_tag *accept_tags, size_t n_accept_tag) { int ret = TAG_MATCH_ERR; int n_set = 0; cJSON *tag_set = NULL; cJSON *tag_set_array = NULL; cJSON *root = cJSON_Parse(value); if (NULL == root) { goto error; } tag_set_array = cJSON_GetObjectItem(root, "tag_sets"); if (NULL == tag_set_array || tag_set_array->type != cJSON_Array) { goto error; } n_set = cJSON_GetArraySize(tag_set_array); for (int i = 0; i < n_set; i++) { tag_set = cJSON_GetArrayItem(tag_set_array, i); if (NULL == tag_set || tag_set->type != cJSON_Array) { goto error; } ret = compare_each_tag_set(tag_set, accept_tags, n_accept_tag); //match or error occurs. if (ret != TAG_MATCH_UNMATCHED) { break; } } error: cJSON_Delete(root); return ret; } void *maat_table_schema_new(cJSON *json, const char *table_name, enum table_type table_type, struct table_manager *tbl_mgr, struct log_handle *logger) { void *schema = NULL; if (table_ops[table_type].new_schema != NULL) { schema = table_ops[table_type].new_schema(json, tbl_mgr, table_name, logger); } return schema; } void maat_table_schema_free(void *schema, enum table_type table_type) { if (NULL == schema) { return; } if (table_ops[table_type].free_schema != NULL) { table_ops[table_type].free_schema(schema); } } static void register_reserved_word(struct maat_kv_store *reserved_word_map) { maat_kv_register(reserved_word_map, "compile", TABLE_TYPE_COMPILE); maat_kv_register(reserved_word_map, "group2compile", TABLE_TYPE_GROUP2COMPILE); maat_kv_register(reserved_word_map, "group2group", TABLE_TYPE_GROUP2GROUP); maat_kv_register(reserved_word_map, "flag", TABLE_TYPE_FLAG); maat_kv_register(reserved_word_map, "flag_plus", TABLE_TYPE_FLAG_PLUS); maat_kv_register(reserved_word_map, "expr", TABLE_TYPE_EXPR); maat_kv_register(reserved_word_map, "expr_plus", TABLE_TYPE_EXPR_PLUS); maat_kv_register(reserved_word_map, "intval", TABLE_TYPE_INTERVAL); maat_kv_register(reserved_word_map, "intval_plus", TABLE_TYPE_INTERVAL_PLUS); maat_kv_register(reserved_word_map, "ip_plus", TABLE_TYPE_IP_PLUS); maat_kv_register(reserved_word_map, "plugin", TABLE_TYPE_PLUGIN); maat_kv_register(reserved_word_map, "ip_plugin", TABLE_TYPE_IP_PLUGIN); maat_kv_register(reserved_word_map, "bool_plugin", TABLE_TYPE_BOOL_PLUGIN); maat_kv_register(reserved_word_map, "fqdn_plugin", TABLE_TYPE_FQDN_PLUGIN); maat_kv_register(reserved_word_map, "virtual", TABLE_TYPE_VIRTUAL); } static int register_tablename2id(cJSON *json, struct maat_kv_store *tablename2id_map, struct log_handle *logger) { cJSON *item = cJSON_GetObjectItem(json, "table_id"); if (NULL == item || item->type != cJSON_Number) { return -1; } int table_id = item->valueint; item = cJSON_GetObjectItem(json, "db_tables"); if (item != NULL && item->type != cJSON_Array) { log_error(logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) has db_tables, but format is invalid, should be array", __FUNCTION__, __LINE__, table_id); return -1; } if (item != NULL) { int n_table_name = cJSON_GetArraySize(item); for (int i = 0; i < n_table_name; i++) { cJSON *tmp_item = cJSON_GetArrayItem(item, i); if (NULL == tmp_item || tmp_item->type != cJSON_String) { log_error(logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) db_tables element format invalid, should be string", __FUNCTION__, __LINE__, table_id); return -1; } if (strlen(tmp_item->valuestring) >= NAME_MAX) { log_error(logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) db_tables element string %s length too long", __FUNCTION__, __LINE__, table_id, tmp_item->valuestring); return -1; } maat_kv_register(tablename2id_map, tmp_item->valuestring, table_id); log_info(logger, MODULE_TABLE, "table_name[%s] -> table_id:[%d]", tmp_item->valuestring, table_id); } } item = cJSON_GetObjectItem(json, "table_name"); if (NULL == item || item->type != cJSON_String) { log_error(logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) has no table_name", __FUNCTION__, __LINE__, table_id); return -1; } if (strlen(item->valuestring) >= NAME_MAX) { log_error(logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_name %s length too long", __FUNCTION__, __LINE__, table_id, item->valuestring); return -1; } maat_kv_register(tablename2id_map, item->valuestring, table_id); log_info(logger, MODULE_TABLE, "table_name[%s] -> table_id:[%d]", item->valuestring, table_id); return 0; } struct maat_table *maat_table_new(cJSON *json, struct maat_kv_store *reserved_word_map, struct log_handle *logger) { struct maat_table *ptable = ALLOC(struct maat_table, 1); int ret = -1; cJSON *item = cJSON_GetObjectItem(json, "table_id"); if (NULL == item || item->type != cJSON_Number) { goto error; } if (item->valueint >= MAX_TABLE_NUM) { log_error(logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) exceed maxium %d", __FUNCTION__, __LINE__, MAX_TABLE_NUM); goto error; } ptable->table_id = item->valueint; item = cJSON_GetObjectItem(json, "table_name"); // already validate in register_tablename2id if (item->type == cJSON_Array) { cJSON *tmp_item = cJSON_GetArrayItem(item, 0); memcpy(ptable->table_name, tmp_item->valuestring, strlen(tmp_item->valuestring)); } else { //cJSON_String memcpy(ptable->table_name, item->valuestring, strlen(item->valuestring)); } item = cJSON_GetObjectItem(json, "table_type"); if (NULL == item || item->type != cJSON_String) { log_error(logger, MODULE_TABLE, "[%s:%d] table:%s has no table_type column", __FUNCTION__, __LINE__, ptable->table_name); goto error; } ret = maat_kv_read(reserved_word_map, item->valuestring, (long long *)&(ptable->table_type)); if (ret < 0) { log_error(logger, MODULE_TABLE, "[%s:%d] table:%s table_type %s is illegal", __FUNCTION__, __LINE__, ptable->table_name, item->valuestring); goto error; } item = cJSON_GetObjectItem(json, "valid_column"); if (NULL == item || item->type != cJSON_Number) { if (ptable->table_type != TABLE_TYPE_VIRTUAL) { log_error(logger, MODULE_TABLE, "[%s:%d] table:%s has no valid column", __FUNCTION__, __LINE__, ptable->table_name); goto error; } } else { ptable->valid_column = item->valueint; } return ptable; error: FREE(ptable); return NULL; } void maat_table_runtime_free(void *runtime, enum table_type table_type) { if (NULL == runtime) { return; } if (table_ops[table_type].free_runtime != NULL) { table_ops[table_type].free_runtime(runtime); } } void maat_table_free(struct maat_table *maat_tbl) { if (NULL == maat_tbl) { return; } if (maat_tbl->runtime != NULL) { maat_table_runtime_free(maat_tbl->runtime, maat_tbl->table_type); maat_tbl->runtime = NULL; } if (maat_tbl->updating_runtime != NULL) { maat_table_runtime_free(maat_tbl->updating_runtime, maat_tbl->table_type); maat_tbl->updating_runtime = NULL; } if (maat_tbl->schema != NULL) { maat_table_schema_free(maat_tbl->schema, maat_tbl->table_type); maat_tbl->schema = NULL; } FREE(maat_tbl); } struct table_manager * table_manager_create(const char *table_info_path, const char *accept_tags, struct maat_garbage_bin *garbage_bin, struct log_handle *logger) { if (NULL == table_info_path) { return NULL; } unsigned char *json_buff = NULL; size_t json_buff_sz = 0; int ret = load_file_to_memory(table_info_path, &json_buff, &json_buff_sz); if (ret < 0) { log_error(logger, MODULE_TABLE, "[%s:%d] Maat read table info %s error.", __FUNCTION__, __LINE__, table_info_path); return NULL; } cJSON *root = NULL; cJSON *json = NULL; root = cJSON_Parse((const char *)json_buff); if (!root) { log_error(logger, MODULE_TABLE, "[%s:%d] error message: %-200.200s", __FUNCTION__, __LINE__, cJSON_GetErrorPtr()); FREE(json_buff); return NULL; } int json_array_size = cJSON_GetArraySize(root); if (json_array_size <= 0) { log_error(logger, MODULE_TABLE, "[%s:%d] invalid json content in %s", __FUNCTION__, __LINE__, table_info_path); FREE(json_buff); cJSON_Delete(root); return NULL; } struct table_manager *tbl_mgr = ALLOC(struct table_manager, 1); tbl_mgr->n_accept_tag = parse_accept_tag(accept_tags, &tbl_mgr->accept_tags, logger); tbl_mgr->logger = logger; tbl_mgr->tablename2id_map = maat_kv_store_new(); tbl_mgr->ref_garbage_bin = garbage_bin; for (int i = 0; i < json_array_size; i++) { json = cJSON_GetArrayItem(root, i); if (json != NULL && json->type == cJSON_Object) { ret = register_tablename2id(json, tbl_mgr->tablename2id_map, logger); if (ret < 0) { log_error(logger, MODULE_TABLE, "[%s:%d] register_tablename2id failed", __FUNCTION__, __LINE__); FREE(json_buff); cJSON_Delete(root); table_manager_destroy(tbl_mgr); return NULL; } } } int default_compile_table_id = -1; int g2g_table_id = -1; struct maat_kv_store *reserved_word_map = maat_kv_store_new(); register_reserved_word(reserved_word_map); for (int i = 0; i < json_array_size; i++) { json = cJSON_GetArrayItem(root, i); if (json != NULL && json->type == cJSON_Object) { struct maat_table *maat_tbl = maat_table_new(json, reserved_word_map, logger); if (NULL == maat_tbl) { ret = -1; goto next; } maat_tbl->schema = maat_table_schema_new(json, maat_tbl->table_name, maat_tbl->table_type, tbl_mgr, logger); if (NULL == maat_tbl->schema) { log_error(logger, MODULE_TABLE, "[%s:%d] Maat table schema new failed, table_name:%s", __FUNCTION__, __LINE__, maat_tbl->table_name); ret = -1; goto next; } log_info(logger, MODULE_TABLE, "successfully register table[%s]->table_id:%d", maat_tbl->table_name, maat_tbl->table_id); if (maat_tbl->table_type == TABLE_TYPE_COMPILE) { if (default_compile_table_id < 0) { default_compile_table_id = maat_tbl->table_id; } else if (maat_tbl->table_id < default_compile_table_id) { default_compile_table_id = maat_tbl->table_id; } } if (maat_tbl->table_type == TABLE_TYPE_GROUP2GROUP) { g2g_table_id = maat_tbl->table_id; } tbl_mgr->tbl[maat_tbl->table_id] = maat_tbl; tbl_mgr->n_table++; } } tbl_mgr->default_compile_table_id = default_compile_table_id; tbl_mgr->g2g_table_id = g2g_table_id; log_info(logger, MODULE_TABLE, "default compile table id: %d", default_compile_table_id); log_info(logger, MODULE_TABLE, "group2group table id: %d", g2g_table_id); next: FREE(json_buff); maat_kv_store_free(reserved_word_map); cJSON_Delete(root); if (ret < 0) { table_manager_destroy(tbl_mgr); return NULL; } return tbl_mgr; } void *maat_table_runtime_new(void *schema, enum table_type table_type, size_t max_thread_num, struct maat_garbage_bin *garbage_bin, struct log_handle *logger) { void *runtime = NULL; if (table_ops[table_type].new_runtime != NULL) { runtime = table_ops[table_type].new_runtime(schema, max_thread_num, garbage_bin, logger); } return runtime; } void garbage_maat_table_runtime_free(void *runtime, void *arg) { enum table_type type = *(enum table_type *)arg; maat_table_runtime_free(runtime, type); } int table_manager_runtime_create(struct table_manager *tbl_mgr, size_t max_thread_num, struct maat_garbage_bin *garbage_bin) { if (NULL == tbl_mgr) { return -1; } assert(tbl_mgr->n_table != 0); size_t i = 0; enum table_type table_type = TABLE_TYPE_INVALID; for (i = 0; i < MAX_TABLE_NUM; i++) { void *schema = table_manager_get_schema(tbl_mgr, i); if (NULL == schema) { continue; } assert(tbl_mgr->tbl[i]->updating_runtime == NULL); table_type = table_manager_get_table_type(tbl_mgr, i); assert(table_type != TABLE_TYPE_INVALID); tbl_mgr->tbl[i]->updating_runtime = maat_table_runtime_new(schema, table_type, max_thread_num, garbage_bin, tbl_mgr->logger); } /* group2compile runtime depends on associated compile runtime, must make sure associated compile runtime already exist */ for (i = 0; i < MAX_TABLE_NUM; i++) { table_type = table_manager_get_table_type(tbl_mgr, i); if (table_type != TABLE_TYPE_GROUP2COMPILE) { continue; } void *schema = table_manager_get_schema(tbl_mgr, i); if (NULL == schema) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] group2compile table(table_id:%d) schema is null", __FUNCTION__, __LINE__, i); continue; } void *g2c_updating_rt = table_manager_get_updating_runtime(tbl_mgr, i); if (NULL == g2c_updating_rt) { continue; } int associated_compile_table_id = group2compile_associated_compile_table_id(schema); void *compile_updating_rt = table_manager_get_updating_runtime(tbl_mgr, associated_compile_table_id); int g2g_group_id = table_manager_get_group2group_table_id(tbl_mgr); void *g2g_updating_rt = table_manager_get_updating_runtime(tbl_mgr, g2g_group_id); group2compile_runtime_init(g2c_updating_rt, compile_updating_rt, g2g_updating_rt); } return 0; } void table_manager_runtime_destroy(struct table_manager *tbl_mgr) { if (NULL == tbl_mgr) { return; } for(size_t i = 0; i < MAX_TABLE_NUM; i++) { void *runtime = table_manager_get_runtime(tbl_mgr, i); if (runtime != NULL) { enum table_type table_type = table_manager_get_table_type(tbl_mgr, i); assert(table_type != TABLE_TYPE_INVALID); maat_table_runtime_free(runtime, table_type); tbl_mgr->tbl[i]->runtime = NULL; } } } void table_manager_destroy(struct table_manager *tbl_mgr) { if (NULL == tbl_mgr) { return; } size_t i = 0; for (i = 0; i < MAX_TABLE_NUM; i++) { maat_table_free(tbl_mgr->tbl[i]); tbl_mgr->tbl[i] = NULL; } if (tbl_mgr->accept_tags != NULL) { for (i = 0; i < tbl_mgr->n_accept_tag; i++) { if (tbl_mgr->accept_tags[i].tag_name != NULL) { FREE(tbl_mgr->accept_tags[i].tag_name); } if (tbl_mgr->accept_tags[i].tag_val != NULL) { FREE(tbl_mgr->accept_tags[i].tag_val); } } FREE(tbl_mgr->accept_tags); } if (tbl_mgr->tablename2id_map != NULL) { maat_kv_store_free(tbl_mgr->tablename2id_map); tbl_mgr->tablename2id_map = NULL; } FREE(tbl_mgr); } size_t table_manager_table_size(struct table_manager *tbl_mgr) { return MAX_TABLE_NUM; } size_t table_manager_table_count(struct table_manager *tbl_mgr) { if (NULL == tbl_mgr) { return 0; } return tbl_mgr->n_table; } int table_manager_get_table_id(struct table_manager *tbl_mgr, const char *name) { if (NULL == tbl_mgr || NULL == name) { return -1; } long long table_id = -1; int ret = maat_kv_read(tbl_mgr->tablename2id_map, name, &table_id); if (ret < 0) { return -1; } return (int)table_id; } const char *table_manager_get_table_name(struct table_manager *tbl_mgr, int table_id) { if (NULL == tbl_mgr || table_id < 0) { return NULL; } if (NULL == tbl_mgr->tbl[table_id]) { return NULL; } return tbl_mgr->tbl[table_id]->table_name; } enum table_type table_manager_get_table_type(struct table_manager *tbl_mgr, int table_id) { if (NULL == tbl_mgr || table_id < 0 || table_id >= MAX_TABLE_NUM) { return TABLE_TYPE_INVALID; } if (NULL == tbl_mgr->tbl[table_id]) { return TABLE_TYPE_INVALID; } return tbl_mgr->tbl[table_id]->table_type; } int table_manager_get_defaut_compile_table_id(struct table_manager *tbl_mgr) { return tbl_mgr->default_compile_table_id; } int table_manager_get_group2group_table_id(struct table_manager *tbl_mgr) { return tbl_mgr->g2g_table_id; } void *table_manager_get_schema(struct table_manager *tbl_mgr, int table_id) { if (NULL == tbl_mgr || table_id < 0 || table_id >= MAX_TABLE_NUM) { return NULL; } if (NULL == tbl_mgr->tbl[table_id]) { return NULL; } return tbl_mgr->tbl[table_id]->schema; } int table_manager_get_valid_column(struct table_manager *tbl_mgr, int table_id) { if (NULL == tbl_mgr || table_id < 0 || table_id >= MAX_TABLE_NUM) { return -1; } if (NULL == tbl_mgr->tbl[table_id]) { return -1; } return tbl_mgr->tbl[table_id]->valid_column; } size_t table_manager_accept_tags_count(struct table_manager *tbl_mgr) { return tbl_mgr->n_accept_tag; } int table_manager_accept_tags_match(struct table_manager *tbl_mgr, const char *tags) { return compare_accept_tag(tags, tbl_mgr->accept_tags, tbl_mgr->n_accept_tag); } void *table_manager_get_runtime(struct table_manager *tbl_mgr, int table_id) { if (NULL == tbl_mgr || (table_id < 0) || (table_id >= MAX_TABLE_NUM)) { return NULL; } if (NULL == tbl_mgr->tbl[table_id]) { return NULL; } return tbl_mgr->tbl[table_id]->runtime; } void *table_manager_get_updating_runtime(struct table_manager *tbl_mgr, int table_id) { if (NULL == tbl_mgr || (table_id < 0) || (table_id >= MAX_TABLE_NUM)) { return NULL; } if (NULL == tbl_mgr->tbl[table_id]) { return NULL; } return tbl_mgr->tbl[table_id]->updating_runtime; } int table_manager_update_runtime(struct table_manager *tbl_mgr, const char *table_name, int table_id, const char *line, int update_type) { void *schema = table_manager_get_schema(tbl_mgr, table_id); if (NULL == schema) { return -1; } void *runtime = NULL; if (update_type == MAAT_UPDATE_TYPE_FULL) { runtime = table_manager_get_updating_runtime(tbl_mgr, table_id); } else { runtime = table_manager_get_runtime(tbl_mgr, table_id); } if (NULL == runtime) { return -1; } int valid_column = table_manager_get_valid_column(tbl_mgr, table_id); if (valid_column < 0) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table:%s has no valid column, can't update runtime", __FUNCTION__, __LINE__, table_name); return -1; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table:%s table_type is invalid, can't update runtime", __FUNCTION__, __LINE__, table_name); return -1; } if (NULL == table_ops[table_type].update_runtime) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table:%s has no update_runtime function, can't update runtime", __FUNCTION__, __LINE__, table_name); return -1; } return table_ops[table_type].update_runtime(runtime, schema, table_name, line, valid_column); } void table_commit_updating_runtime(struct table_manager *tbl_mgr, int table_id, long long maat_rt_version) { void *updating_rt = table_manager_get_updating_runtime(tbl_mgr, table_id); if (NULL == updating_rt) { return; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't commit runtime", __FUNCTION__, __LINE__, table_id); return; } struct maat_table *ptable = tbl_mgr->tbl[table_id]; if ( table_ops[table_type].commit_runtime != NULL) { table_ops[table_type].commit_runtime(updating_rt, ptable->table_name, maat_rt_version); } void *runtime = table_manager_get_runtime(tbl_mgr, table_id); tbl_mgr->tbl[table_id]->runtime = updating_rt; if (runtime != NULL) { enum table_type *arg = ALLOC(enum table_type, 1); *arg = table_type; maat_garbage_bagging(tbl_mgr->ref_garbage_bin, runtime, arg, garbage_maat_table_runtime_free); } tbl_mgr->tbl[table_id]->updating_runtime = NULL; } void table_commit_runtime(struct table_manager *tbl_mgr, int table_id, long long maat_rt_version) { void *runtime = table_manager_get_runtime(tbl_mgr, table_id); if (NULL == runtime) { return; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't commit runtime", __FUNCTION__, __LINE__, table_id); return; } struct maat_table *ptable = tbl_mgr->tbl[table_id]; if (table_ops[table_type].commit_runtime != NULL) { table_ops[table_type].commit_runtime(runtime, ptable->table_name, maat_rt_version); } } void table_manager_commit_runtime(struct table_manager *tbl_mgr, int table_id, int update_type, long long maat_rt_version) { if (NULL == tbl_mgr || table_id < 0) { return; } if (update_type == MAAT_UPDATE_TYPE_FULL) { table_commit_updating_runtime(tbl_mgr, table_id, maat_rt_version); } else { table_commit_runtime(tbl_mgr, table_id, maat_rt_version); } } long long table_manager_runtime_rule_count(struct table_manager *tbl_mgr, int table_id) { void *runtime = table_manager_get_runtime(tbl_mgr, table_id); if (NULL == runtime) { return 0; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't update runtime", __FUNCTION__, __LINE__, table_id); return 0; } if (NULL == table_ops[table_type].rule_count) { return 0; } return table_ops[table_type].rule_count(runtime); } long long table_manager_runtime_scan_count(struct table_manager *tbl_mgr, int table_id) { void *runtime = table_manager_get_runtime(tbl_mgr, table_id); if (NULL == runtime) { return 0; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't get scan count", __FUNCTION__, __LINE__, table_id); return 0; } if (NULL == table_ops[table_type].scan_count) { return 0; } return table_ops[table_type].scan_count(runtime); } long long table_manager_runtime_scan_cpu_time(struct table_manager *tbl_mgr, int table_id) { void *runtime = table_manager_get_runtime(tbl_mgr, table_id); if (NULL == runtime) { return 0; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't get scan cpu time", __FUNCTION__, __LINE__, table_id); return 0; } if (NULL == table_ops[table_type].scan_cpu_time) { return 0; } return table_ops[table_type].scan_cpu_time(runtime); } long long table_manager_runtime_hit_count(struct table_manager *tbl_mgr, int table_id) { void *runtime = table_manager_get_runtime(tbl_mgr, table_id); if (NULL == runtime) { return 0; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't get hit count", __FUNCTION__, __LINE__, table_id); return 0; } if (NULL == table_ops[table_type].hit_count) { return 0; } return table_ops[table_type].hit_count(runtime); } long long table_manager_runtime_update_err_count(struct table_manager *tbl_mgr, int table_id) { void *runtime = table_manager_get_runtime(tbl_mgr, table_id); if (NULL == runtime) { return 0; } enum table_type table_type = table_manager_get_table_type(tbl_mgr, table_id); if (table_type == TABLE_TYPE_INVALID) { log_error(tbl_mgr->logger, MODULE_TABLE, "[%s:%d] table(table_id:%d) table_type is invalid, can't get hit count", __FUNCTION__, __LINE__, table_id); return 0; } if (NULL == table_ops[table_type].update_err_count) { return 0; } return table_ops[table_type].update_err_count(runtime); }