From 34a6935b77abf8d4121bdeefed088fe52675c9a9 Mon Sep 17 00:00:00 2001 From: Kamil Cudnik Date: Tue, 17 Nov 2020 22:03:16 +0100 Subject: [PATCH] [meta] Use custom hash in SaiObjectCollection (#709) Currently unordered_map with std::string key is used, but since sai_serialize_object_meta_key is expensive, it make sense to keep original meta_key as key and write custom hash function. For 100k routes, metadata speeds up 3x when using custom hash. --- meta/Makefile.am | 1 + meta/Meta.cpp | 248 +++++++++++++++++------------------ meta/Meta.h | 2 +- meta/MetaKeyHasher.cpp | 210 +++++++++++++++++++++++++++++ meta/MetaKeyHasher.h | 20 +++ meta/SaiObject.cpp | 9 +- meta/SaiObject.h | 4 - meta/SaiObjectCollection.cpp | 72 ++++------ meta/SaiObjectCollection.h | 10 +- meta/tests.cpp | 81 ++++++++++-- 10 files changed, 452 insertions(+), 205 deletions(-) create mode 100644 meta/MetaKeyHasher.cpp create mode 100644 meta/MetaKeyHasher.h diff --git a/meta/Makefile.am b/meta/Makefile.am index 17d6434b47db..ba1fb39747e2 100644 --- a/meta/Makefile.am +++ b/meta/Makefile.am @@ -84,6 +84,7 @@ libsaimetadata_la_SOURCES = \ SaiObject.cpp \ SaiObjectCollection.cpp \ PortRelatedSet.cpp \ + MetaKeyHasher.cpp \ Meta.cpp diff --git a/meta/Meta.cpp b/meta/Meta.cpp index 4a422f779694..74a1d499dbdb 100644 --- a/meta/Meta.cpp +++ b/meta/Meta.cpp @@ -2897,11 +2897,8 @@ void Meta::clean_after_switch_remove( } } - for (auto& key: m_saiObjectCollection.getAllKeys()) + for (auto& mk: m_saiObjectCollection.getAllKeys()) { - sai_object_meta_key_t mk; - sai_deserialize_object_meta_key(key, mk); - // we guarantee that switch_id is first in the key structure so we can // use that as object_id as well @@ -2920,11 +2917,10 @@ sai_status_t Meta::meta_generic_validation_remove( { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(meta_key); - - if (!m_saiObjectCollection.objectExists(key)) + if (!m_saiObjectCollection.objectExists(meta_key)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3073,9 +3069,7 @@ bool Meta::meta_is_object_in_default_state( meta_key.objecttype = objectTypeQuery(oid); meta_key.objectkey.key.object_id = oid; - std::string key = sai_serialize_object_meta_key(meta_key); - - if (!m_saiObjectCollection.objectExists(key)) + if (!m_saiObjectCollection.objectExists(meta_key)) { SWSS_LOG_WARN("object %s don't exists in local database, bug!", sai_serialize_object_id(oid).c_str()); @@ -3205,11 +3199,10 @@ sai_status_t Meta::meta_sai_validate_oid( sai_object_meta_key_t meta_key_oid = { .objecttype = expected, .objectkey = { .key = { .object_id = oid } } }; - std::string key_oid = sai_serialize_object_meta_key(meta_key_oid); - - if (!m_saiObjectCollection.objectExists(key_oid)) + if (!m_saiObjectCollection.objectExists(meta_key_oid)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_oid.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_oid).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3479,13 +3472,12 @@ sai_status_t Meta::meta_sai_validate_fdb_entry( sai_object_meta_key_t meta_key_fdb = { .objecttype = SAI_OBJECT_TYPE_FDB_ENTRY, .objectkey = { .key = { .fdb_entry = *fdb_entry } } }; - std::string key_fdb = sai_serialize_object_meta_key(meta_key_fdb); - if (create) { - if (m_saiObjectCollection.objectExists(key_fdb)) + if (m_saiObjectCollection.objectExists(meta_key_fdb)) { - SWSS_LOG_ERROR("object key %s already exists", key_fdb.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -3495,9 +3487,10 @@ sai_status_t Meta::meta_sai_validate_fdb_entry( // set, get, remove - if (!m_saiObjectCollection.objectExists(key_fdb) && !get) + if (!m_saiObjectCollection.objectExists(meta_key_fdb) && !get) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_fdb.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3550,11 +3543,10 @@ sai_status_t Meta::meta_sai_validate_mcast_fdb_entry( sai_object_meta_key_t meta_key_bv = { .objecttype = object_type, .objectkey = { .key = { .object_id = bv_id } } }; - std::string key_bv = sai_serialize_object_meta_key(meta_key_bv); - - if (!m_saiObjectCollection.objectExists(key_bv)) + if (!m_saiObjectCollection.objectExists(meta_key_bv)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_bv.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_bv).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3563,13 +3555,12 @@ sai_status_t Meta::meta_sai_validate_mcast_fdb_entry( sai_object_meta_key_t meta_key_fdb = { .objecttype = SAI_OBJECT_TYPE_MCAST_FDB_ENTRY, .objectkey = { .key = { .mcast_fdb_entry = *mcast_fdb_entry } } }; - std::string key_fdb = sai_serialize_object_meta_key(meta_key_fdb); - if (create) { - if (m_saiObjectCollection.objectExists(key_fdb)) + if (m_saiObjectCollection.objectExists(meta_key_fdb)) { - SWSS_LOG_ERROR("object key %s already exists", key_fdb.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -3579,9 +3570,10 @@ sai_status_t Meta::meta_sai_validate_mcast_fdb_entry( // set, get, remove - if (!m_saiObjectCollection.objectExists(key_fdb) && !get) + if (!m_saiObjectCollection.objectExists(meta_key_fdb) && !get) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_fdb.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3648,24 +3640,23 @@ sai_status_t Meta::meta_sai_validate_neighbor_entry( sai_object_meta_key_t meta_key_rif = { .objecttype = expected, .objectkey = { .key = { .object_id = rif } } }; - std::string key_rif = sai_serialize_object_meta_key(meta_key_rif); - if (!m_saiObjectCollection.objectExists(key_rif)) + if (!m_saiObjectCollection.objectExists(meta_key_rif)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_rif.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_rif).c_str()); return SAI_STATUS_INVALID_PARAMETER; } sai_object_meta_key_t meta_key_neighbor = { .objecttype = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, .objectkey = { .key = { .neighbor_entry = *neighbor_entry } } }; - std::string key_neighbor = sai_serialize_object_meta_key(meta_key_neighbor); - if (create) { - if (m_saiObjectCollection.objectExists(key_neighbor)) + if (m_saiObjectCollection.objectExists(meta_key_neighbor)) { - SWSS_LOG_ERROR("object key %s already exists", key_neighbor.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_neighbor).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -3675,9 +3666,10 @@ sai_status_t Meta::meta_sai_validate_neighbor_entry( // set, get, remove - if (!m_saiObjectCollection.objectExists(key_neighbor)) + if (!m_saiObjectCollection.objectExists(meta_key_neighbor)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_neighbor.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_neighbor).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3756,11 +3748,10 @@ sai_status_t Meta::meta_sai_validate_route_entry( sai_object_meta_key_t meta_key_vr = { .objecttype = expected, .objectkey = { .key = { .object_id = vr } } }; - std::string key_vr = sai_serialize_object_meta_key(meta_key_vr); - - if (!m_saiObjectCollection.objectExists(key_vr)) + if (!m_saiObjectCollection.objectExists(meta_key_vr)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_vr.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_vr).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3769,13 +3760,12 @@ sai_status_t Meta::meta_sai_validate_route_entry( sai_object_meta_key_t meta_key_route = { .objecttype = SAI_OBJECT_TYPE_ROUTE_ENTRY, .objectkey = { .key = { .route_entry = *route_entry } } }; - std::string key_route = sai_serialize_object_meta_key(meta_key_route); - if (create) { - if (m_saiObjectCollection.objectExists(key_route)) + if (m_saiObjectCollection.objectExists(meta_key_route)) { - SWSS_LOG_ERROR("object key %s already exists", key_route.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_route).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -3785,9 +3775,10 @@ sai_status_t Meta::meta_sai_validate_route_entry( // set, get, remove - if (!m_saiObjectCollection.objectExists(key_route)) + if (!m_saiObjectCollection.objectExists(meta_key_route)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_route.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_route).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3880,11 +3871,10 @@ sai_status_t Meta::meta_sai_validate_l2mc_entry( sai_object_meta_key_t meta_key_bv = { .objecttype = object_type, .objectkey = { .key = { .object_id = bv_id } } }; - std::string key_bv = sai_serialize_object_meta_key(meta_key_bv); - - if (!m_saiObjectCollection.objectExists(key_bv)) + if (!m_saiObjectCollection.objectExists(meta_key_bv)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_bv.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_bv).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -3893,13 +3883,12 @@ sai_status_t Meta::meta_sai_validate_l2mc_entry( sai_object_meta_key_t meta_key_route = { .objecttype = SAI_OBJECT_TYPE_L2MC_ENTRY, .objectkey = { .key = { .l2mc_entry = *l2mc_entry } } }; - std::string key_route = sai_serialize_object_meta_key(meta_key_route); - if (create) { - if (m_saiObjectCollection.objectExists(key_route)) + if (m_saiObjectCollection.objectExists(meta_key_route)) { - SWSS_LOG_ERROR("object key %s already exists", key_route.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_route).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -3909,9 +3898,10 @@ sai_status_t Meta::meta_sai_validate_l2mc_entry( // set, get, remove - if (!m_saiObjectCollection.objectExists(key_route)) + if (!m_saiObjectCollection.objectExists(meta_key_route)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_route.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_route).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -4004,11 +3994,10 @@ sai_status_t Meta::meta_sai_validate_ipmc_entry( sai_object_meta_key_t meta_key_bv = { .objecttype = object_type, .objectkey = { .key = { .object_id = vr_id } } }; - std::string key_bv = sai_serialize_object_meta_key(meta_key_bv); - - if (!m_saiObjectCollection.objectExists(key_bv)) + if (!m_saiObjectCollection.objectExists(meta_key_bv)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_bv.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_bv).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -4017,13 +4006,12 @@ sai_status_t Meta::meta_sai_validate_ipmc_entry( sai_object_meta_key_t meta_key_route = { .objecttype = SAI_OBJECT_TYPE_IPMC_ENTRY, .objectkey = { .key = { .ipmc_entry = *ipmc_entry } } }; - std::string key_route = sai_serialize_object_meta_key(meta_key_route); - if (create) { - if (m_saiObjectCollection.objectExists(key_route)) + if (m_saiObjectCollection.objectExists(meta_key_route)) { - SWSS_LOG_ERROR("object key %s already exists", key_route.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_route).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -4033,9 +4021,10 @@ sai_status_t Meta::meta_sai_validate_ipmc_entry( // set, get, remove - if (!m_saiObjectCollection.objectExists(key_route)) + if (!m_saiObjectCollection.objectExists(meta_key_route)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_route.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_route).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -4088,11 +4077,10 @@ sai_status_t Meta::meta_sai_validate_nat_entry( // check if virtual router exists sai_object_meta_key_t meta_key_vr = { .objecttype = expected, .objectkey = { .key = { .object_id = vr } } }; - std::string key_vr = sai_serialize_object_meta_key(meta_key_vr); - - if (!m_saiObjectCollection.objectExists(key_vr)) + if (!m_saiObjectCollection.objectExists(meta_key_vr)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_vr.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_vr).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -4100,13 +4088,12 @@ sai_status_t Meta::meta_sai_validate_nat_entry( // check if NAT entry exists sai_object_meta_key_t meta_key_nat = { .objecttype = SAI_OBJECT_TYPE_NAT_ENTRY, .objectkey = { .key = { .nat_entry = *nat_entry } } }; - std::string key_nat = sai_serialize_object_meta_key(meta_key_nat); - if (create) { - if (m_saiObjectCollection.objectExists(key_nat)) + if (m_saiObjectCollection.objectExists(meta_key_nat)) { - SWSS_LOG_ERROR("object key %s already exists", key_nat.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key_nat).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -4115,9 +4102,10 @@ sai_status_t Meta::meta_sai_validate_nat_entry( } // set, get, remove - if (!m_saiObjectCollection.objectExists(key_nat)) + if (!m_saiObjectCollection.objectExists(meta_key_nat)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key_nat.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key_nat).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -4658,11 +4646,11 @@ sai_status_t Meta::meta_generic_validation_create( if (info->isnonobjectid) { // just sanity check if object already exists - std::string key = sai_serialize_object_meta_key(meta_key); - if (m_saiObjectCollection.objectExists(key)) + if (m_saiObjectCollection.objectExists(meta_key)) { - SWSS_LOG_ERROR("object key %s already exists", key.c_str()); + SWSS_LOG_ERROR("object key %s already exists", + sai_serialize_object_meta_key(meta_key).c_str()); return SAI_STATUS_ITEM_ALREADY_EXISTS; } @@ -5293,9 +5281,8 @@ sai_status_t Meta::meta_generic_validation_set( if (get_object_previous_attr(meta_key, md) == NULL) { - std::string key = sai_serialize_object_meta_key(meta_key); - - META_LOG_WARN(md, "set for conditional, but not found in local db, object %s created on switch ?", key.c_str()); + META_LOG_WARN(md, "set for conditional, but not found in local db, object %s created on switch ?", + sai_serialize_object_meta_key(meta_key).c_str()); } else { @@ -5307,11 +5294,10 @@ sai_status_t Meta::meta_generic_validation_set( // check if object on which we perform operation exists - std::string key = sai_serialize_object_meta_key(meta_key); - - if (!m_saiObjectCollection.objectExists(key)) + if (!m_saiObjectCollection.objectExists(meta_key)) { - META_LOG_ERROR(md, "object key %s doesn't exist", key.c_str()); + META_LOG_ERROR(md, "object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -5320,7 +5306,8 @@ sai_status_t Meta::meta_generic_validation_set( if (info->isnonobjectid) { - SWSS_LOG_DEBUG("object key exists: %s", key.c_str()); + SWSS_LOG_DEBUG("object key exists: %s", + sai_serialize_object_meta_key(meta_key).c_str()); } else { @@ -5424,10 +5411,9 @@ sai_status_t Meta::meta_generic_validation_get( // (this will not respect create_only with default) if (get_object_previous_attr(meta_key, md) == NULL) { - std::string key = sai_serialize_object_meta_key(meta_key); - // XXX produces too much noise - // META_LOG_WARN(md, "get for conditional, but not found in local db, object %s created on switch ?", key.c_str()); + // META_LOG_WARN(md, "get for conditional, but not found in local db, object %s created on switch ?", + // sai_serialize_object_meta_key(meta_key).c_str()); } else { @@ -5607,11 +5593,10 @@ sai_status_t Meta::meta_generic_validation_get( } } - std::string key = sai_serialize_object_meta_key(meta_key); - - if (!m_saiObjectCollection.objectExists(key)) + if (!m_saiObjectCollection.objectExists(meta_key)) { - SWSS_LOG_ERROR("object key %s doesn't exist", key.c_str()); + SWSS_LOG_ERROR("object key %s doesn't exist", + sai_serialize_object_meta_key(meta_key).c_str()); return SAI_STATUS_INVALID_PARAMETER; } @@ -5620,7 +5605,8 @@ sai_status_t Meta::meta_generic_validation_get( if (info->isnonobjectid) { - SWSS_LOG_DEBUG("object key exists: %s", key.c_str()); + SWSS_LOG_DEBUG("object key exists: %s", + sai_serialize_object_meta_key(meta_key).c_str()); } else { @@ -6342,14 +6328,13 @@ void Meta::meta_generic_validation_post_get_objlist( * whether default value is present and it's const NULL. */ - if (!SAI_HAS_FLAG_READ_ONLY(md.flags) && md.allowedobjecttypeslength) // md.isoidattribute) + if (!SAI_HAS_FLAG_READ_ONLY(md.flags) && md.isoidattribute) { if (get_object_previous_attr(meta_key, md) == NULL) { - std::string key = sai_serialize_object_meta_key(meta_key); - // XXX produces too much noise - // META_LOG_WARN(md, "post get, not in local db, FIX snoop!: %s", key.c_str()); + // META_LOG_WARN(md, "post get, not in local db, FIX snoop!: %s", + // sai_serialize_object_meta_key(meta_key).c_str()); } } @@ -6479,9 +6464,7 @@ void Meta::meta_generic_validation_post_create( { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(meta_key); - - if (m_saiObjectCollection.objectExists(key)) + if (m_saiObjectCollection.objectExists(meta_key)) { if (m_warmBoot && meta_key.objecttype == SAI_OBJECT_TYPE_SWITCH) { @@ -6489,7 +6472,8 @@ void Meta::meta_generic_validation_post_create( } else { - SWSS_LOG_ERROR("object key %s already exists (vendor bug?)", key.c_str()); + SWSS_LOG_ERROR("object key %s already exists (vendor bug?)", + sai_serialize_object_meta_key(meta_key).c_str()); // this may produce inconsistency } @@ -6600,7 +6584,7 @@ void Meta::meta_generic_validation_post_create( m_warmBoot = false; } - bool haskeys; + bool haskeys = false; for (uint32_t idx = 0; idx < attr_count; ++idx) { @@ -6776,7 +6760,7 @@ void Meta::meta_generic_validation_post_set( * if there is default value and if it's const. */ - if (!SAI_HAS_FLAG_READ_ONLY(md.flags) && md.allowedobjecttypeslength) // md.isoidattribute) + if (!SAI_HAS_FLAG_READ_ONLY(md.flags) && md.isoidattribute) { if ((get_object_previous_attr(meta_key, md) == NULL) && (md.defaultvaluetype != SAI_DEFAULT_VALUE_TYPE_CONST && @@ -6786,10 +6770,9 @@ void Meta::meta_generic_validation_post_set( * If default value type will be internal then we should warn. */ - std::string key = sai_serialize_object_meta_key(meta_key); - // XXX produces too much noise - // META_LOG_WARN(md, "post set, not in local db, FIX snoop!: %s", key.c_str()); + // META_LOG_WARN(md, "post set, not in local db, FIX snoop!: %s", + // sai_serialize_object_meta_key(meta_key).c_str()); } } @@ -7095,7 +7078,8 @@ void Meta::meta_sai_on_fdb_flush_event_consolidated( if (!fdbTypeAttr) { - SWSS_LOG_ERROR("FATAL: missing SAI_FDB_ENTRY_ATTR_TYPE on %s! bug! skipping flush", fdb->getStrMetaKey().c_str()); + SWSS_LOG_ERROR("FATAL: missing SAI_FDB_ENTRY_ATTR_TYPE on %s! bug! skipping flush", + sai_serialize_object_meta_key(fdb->getMetaKey()).c_str()); continue; } @@ -7137,7 +7121,7 @@ void Meta::meta_sai_on_fdb_flush_event_consolidated( // this fdb entry is matching, removing - SWSS_LOG_INFO("removing %s", fdb->getStrMetaKey().c_str()); + SWSS_LOG_INFO("removing %s", sai_serialize_object_meta_key(meta_key_fdb).c_str()); // since meta_generic_validation_post_remove also modifies m_saiObjectCollection // we need to push this to a vector and remove in next loop @@ -7197,8 +7181,6 @@ void Meta::meta_sai_on_fdb_event_single( const sai_object_meta_key_t meta_key_fdb = { .objecttype = SAI_OBJECT_TYPE_FDB_ENTRY, .objectkey = { .key = { .fdb_entry = data.fdb_entry } } }; - std::string key_fdb = sai_serialize_object_meta_key(meta_key_fdb); - /* * Because we could receive fdb event's before orch agent will query or * create bridge/vlan/bridge port we should snoop here new OIDs and put @@ -7232,9 +7214,10 @@ void Meta::meta_sai_on_fdb_event_single( { case SAI_FDB_EVENT_LEARNED: - if (m_saiObjectCollection.objectExists(key_fdb)) + if (m_saiObjectCollection.objectExists(meta_key_fdb)) { - SWSS_LOG_WARN("object key %s alearedy exists, but received LEARNED event", key_fdb.c_str()); + SWSS_LOG_WARN("object key %s alearedy exists, but received LEARNED event", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); break; } @@ -7264,7 +7247,9 @@ void Meta::meta_sai_on_fdb_event_single( } else { - SWSS_LOG_ERROR("failed to insert %s received in notification: %s", key_fdb.c_str(), sai_serialize_status(status).c_str()); + SWSS_LOG_ERROR("failed to insert %s received in notification: %s", + sai_serialize_object_meta_key(meta_key_fdb).c_str(), + sai_serialize_status(status).c_str()); } } @@ -7272,9 +7257,10 @@ void Meta::meta_sai_on_fdb_event_single( case SAI_FDB_EVENT_AGED: - if (!m_saiObjectCollection.objectExists(key_fdb)) + if (!m_saiObjectCollection.objectExists(meta_key_fdb)) { - SWSS_LOG_WARN("object key %s doesn't exist but received AGED event", key_fdb.c_str()); + SWSS_LOG_WARN("object key %s doesn't exist but received AGED event", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); break; } @@ -7290,9 +7276,10 @@ void Meta::meta_sai_on_fdb_event_single( break; } - if (!m_saiObjectCollection.objectExists(key_fdb)) + if (!m_saiObjectCollection.objectExists(meta_key_fdb)) { - SWSS_LOG_WARN("object key %s doesn't exist but received FLUSHED event", key_fdb.c_str()); + SWSS_LOG_WARN("object key %s doesn't exist but received FLUSHED event", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); break; } @@ -7302,9 +7289,10 @@ void Meta::meta_sai_on_fdb_event_single( case SAI_FDB_EVENT_MOVE: - if (!m_saiObjectCollection.objectExists(key_fdb)) + if (!m_saiObjectCollection.objectExists(meta_key_fdb)) { - SWSS_LOG_WARN("object key %s doesn't exist but received FDB MOVE event", key_fdb.c_str()); + SWSS_LOG_WARN("object key %s doesn't exist but received FDB MOVE event", + sai_serialize_object_meta_key(meta_key_fdb).c_str()); break; } @@ -7318,7 +7306,9 @@ void Meta::meta_sai_on_fdb_event_single( if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("object key %s FDB MOVE event, SET validateion failed on attr.id = %d", key_fdb.c_str(), attr.id); + SWSS_LOG_ERROR("object key %s FDB MOVE event, SET validateion failed on attr.id = %d", + sai_serialize_object_meta_key(meta_key_fdb).c_str(), + attr.id); continue; } @@ -7550,7 +7540,7 @@ int32_t Meta::getObjectReferenceCount( } bool Meta::objectExists( - _In_ const std::string& mk) const + _In_ const sai_object_meta_key_t& mk) const { SWSS_LOG_ENTER(); @@ -7586,7 +7576,7 @@ void Meta::populate( // make references and objects from object id - if (!m_saiObjectCollection.objectExists(key.first)) + if (!m_saiObjectCollection.objectExists(mk)) m_saiObjectCollection.createObject(mk); auto info = sai_metadata_get_object_type_info(mk.objecttype); @@ -7619,7 +7609,7 @@ void Meta::populate( m_oids.objectReferenceInsert(mk.objectkey.key.object_id); } - bool haskeys; + bool haskeys = false; for (uint32_t idx = 0; idx < attr_count; ++idx) { diff --git a/meta/Meta.h b/meta/Meta.h index 498ce11ea3c3..b0b494308527 100644 --- a/meta/Meta.h +++ b/meta/Meta.h @@ -411,7 +411,7 @@ namespace saimeta _In_ sai_object_id_t oid) const; bool objectExists( - _In_ const std::string& mk) const; + _In_ const sai_object_meta_key_t& mk) const; private: // port helpers diff --git a/meta/MetaKeyHasher.cpp b/meta/MetaKeyHasher.cpp new file mode 100644 index 000000000000..91bf3b4ca26e --- /dev/null +++ b/meta/MetaKeyHasher.cpp @@ -0,0 +1,210 @@ +#include "MetaKeyHasher.h" +#include "sai_serialize.h" + +#include "swss/logger.h" + +#include + +using namespace saimeta; + +static bool operator==( + _In_ const sai_fdb_entry_t& a, + _In_ const sai_fdb_entry_t& b) +{ + SWSS_LOG_ENTER(); + + return a.switch_id == b.switch_id && + a.bv_id == b.bv_id && + memcmp(a.mac_address, b.mac_address, sizeof(a.mac_address)) == 0; +} + +static bool operator==( + _In_ const sai_route_entry_t& a, + _In_ const sai_route_entry_t& b) +{ + // SWSS_LOG_ENTER(); // disabled for performance reasons + + bool part = a.switch_id == b.switch_id && + a.vr_id == b.vr_id && + a.destination.addr_family == b.destination.addr_family; + + if (a.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { + return part && + a.destination.addr.ip4 == b.destination.addr.ip4 && + a.destination.mask.ip4 == b.destination.mask.ip4; + } + + if (a.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV6) + { + return part && + memcmp(a.destination.addr.ip6, b.destination.addr.ip6, sizeof(b.destination.addr.ip6)) == 0 && + memcmp(a.destination.mask.ip6, b.destination.mask.ip6, sizeof(b.destination.mask.ip6)) == 0; + } + + return part; +} + +static bool operator==( + _In_ const sai_neighbor_entry_t& a, + _In_ const sai_neighbor_entry_t& b) +{ + SWSS_LOG_ENTER(); + + bool part = a.switch_id == b.switch_id && + a.rif_id == b.rif_id && + a.ip_address.addr_family == b.ip_address.addr_family; + + if (a.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + return part && a.ip_address.addr.ip4 == b.ip_address.addr.ip4; + + if (a.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV6) + return part && memcmp(a.ip_address.addr.ip6, b.ip_address.addr.ip6, sizeof(b.ip_address.addr.ip6)) == 0; + + return part; +} + +static bool operator==( + _In_ const sai_nat_entry_t& a, + _In_ const sai_nat_entry_t& b) +{ + SWSS_LOG_ENTER(); + + // we can't use mem compare, since some fields will be padded and they + // could contain garbage + + return a.switch_id == b.switch_id && + a.vr_id == b.vr_id && + a.nat_type == b.nat_type && + a.data.key.src_ip == b.data.key.src_ip && + a.data.key.dst_ip == b.data.key.dst_ip && + a.data.key.proto == b.data.key.proto && + a.data.key.l4_src_port == b.data.key.l4_src_port && + a.data.key.l4_dst_port == b.data.key.l4_dst_port && + a.data.mask.src_ip == b.data.mask.src_ip && + a.data.mask.dst_ip == b.data.mask.dst_ip && + a.data.mask.proto == b.data.mask.proto && + a.data.mask.l4_src_port == b.data.mask.l4_src_port && + a.data.mask.l4_dst_port == b.data.mask.l4_dst_port; +} + +bool MetaKeyHasher::operator()( + _In_ const sai_object_meta_key_t& a, + _In_ const sai_object_meta_key_t& b) const +{ + // SWSS_LOG_ENTER(); // disabled for performance reasons + + if (a.objecttype != b.objecttype) + return false; + + auto meta = sai_metadata_get_object_type_info(a.objecttype); + + if (meta && meta->isobjectid) + return a.objectkey.key.object_id == b.objectkey.key.object_id; + + if (a.objecttype == SAI_OBJECT_TYPE_ROUTE_ENTRY) + return a.objectkey.key.route_entry == b.objectkey.key.route_entry; + + if (a.objecttype == SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) + return a.objectkey.key.neighbor_entry == b.objectkey.key.neighbor_entry; + + if (a.objecttype == SAI_OBJECT_TYPE_FDB_ENTRY) + return a.objectkey.key.fdb_entry == b.objectkey.key.fdb_entry; + + if (a.objecttype == SAI_OBJECT_TYPE_NAT_ENTRY) + return a.objectkey.key.nat_entry == b.objectkey.key.nat_entry; + + SWSS_LOG_THROW("not implemented: %s", + sai_serialize_object_meta_key(a).c_str()); +} + +static_assert(sizeof(std::size_t) >= sizeof(uint32_t), "size_t must be at least 32 bits"); + +static inline std::size_t sai_get_hash( + _In_ const sai_route_entry_t& re) +{ + // SWSS_LOG_ENTER(); // disabled for performance reasons + + if (re.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { + return re.destination.addr.ip4; + } + + if (re.destination.addr_family == SAI_IP_ADDR_FAMILY_IPV6) + { + const uint32_t* ip6 = (const uint32_t*)re.destination.addr.ip6; + + return ip6[0] ^ ip6[1] ^ ip6[2] ^ ip6[3]; + } + + return re.destination.addr_family; +} + +static inline std::size_t sai_get_hash( + _In_ const sai_neighbor_entry_t& ne) +{ + SWSS_LOG_ENTER(); + + if (ne.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { + return ne.ip_address.addr.ip4; + } + + if (ne.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV6) + { + const uint32_t* ip6 = (const uint32_t*)ne.ip_address.addr.ip6; + + return ip6[0] ^ ip6[1] ^ ip6[2] ^ ip6[3]; + } + + return ne.ip_address.addr_family; +} + +static inline std::size_t sai_get_hash( + _In_ const sai_fdb_entry_t& fe) +{ + SWSS_LOG_ENTER(); + + return *(const uint32_t*)(&fe.mac_address[2]); +} + +static inline std::size_t sai_get_hash( + _In_ const sai_nat_entry_t& ne) +{ + SWSS_LOG_ENTER(); + + // TODO revisit - may depend on nat_type + + return ne.data.key.src_ip ^ ne.data.key.dst_ip; +} + +std::size_t MetaKeyHasher::operator()( + _In_ const sai_object_meta_key_t& k) const +{ + // SWSS_LOG_ENTER(); // disabled for performance reasons + + auto meta = sai_metadata_get_object_type_info(k.objecttype); + + if (meta && meta->isobjectid) + { + return k.objectkey.key.object_id; + } + + switch (k.objecttype) + { + case SAI_OBJECT_TYPE_ROUTE_ENTRY: + return sai_get_hash(k.objectkey.key.route_entry); + + case SAI_OBJECT_TYPE_NEIGHBOR_ENTRY: + return sai_get_hash(k.objectkey.key.neighbor_entry); + + case SAI_OBJECT_TYPE_FDB_ENTRY: + return sai_get_hash(k.objectkey.key.fdb_entry); + + case SAI_OBJECT_TYPE_NAT_ENTRY: + return sai_get_hash(k.objectkey.key.nat_entry); + + default: + SWSS_LOG_THROW("not handled: %s", sai_serialize_object_type(k.objecttype).c_str()); + } +} diff --git a/meta/MetaKeyHasher.h b/meta/MetaKeyHasher.h new file mode 100644 index 000000000000..f7a2b4e2c21c --- /dev/null +++ b/meta/MetaKeyHasher.h @@ -0,0 +1,20 @@ +#pragma once + +extern "C" { +#include "saimetadata.h" +} + +#include + +namespace saimeta +{ + struct MetaKeyHasher + { + std::size_t operator()( + _In_ const sai_object_meta_key_t& k) const; + + bool operator()( + _In_ const sai_object_meta_key_t& a, + _In_ const sai_object_meta_key_t& b) const; + }; +} diff --git a/meta/SaiObject.cpp b/meta/SaiObject.cpp index 3ca7b60a88bd..253ab91c0412 100644 --- a/meta/SaiObject.cpp +++ b/meta/SaiObject.cpp @@ -12,7 +12,7 @@ SaiObject::SaiObject( { SWSS_LOG_ENTER(); - m_strMetaKey = sai_serialize_object_meta_key(metaKey); + // empty } sai_object_type_t SaiObject::getObjectType() const @@ -30,13 +30,6 @@ bool SaiObject::hasAttr( return m_attrs.find(id) != m_attrs.end(); } -const std::string SaiObject::getStrMetaKey() const -{ - SWSS_LOG_ENTER(); - - return m_strMetaKey; -} - const sai_object_meta_key_t& SaiObject::getMetaKey() const { SWSS_LOG_ENTER(); diff --git a/meta/SaiObject.h b/meta/SaiObject.h index 4216003eeaed..68cdf182f109 100644 --- a/meta/SaiObject.h +++ b/meta/SaiObject.h @@ -29,8 +29,6 @@ namespace saimeta bool hasAttr( _In_ sai_attr_id_t id) const; - const std::string getStrMetaKey() const; - const sai_object_meta_key_t& getMetaKey() const; void setAttr( @@ -49,8 +47,6 @@ namespace saimeta sai_object_meta_key_t m_metaKey; - std::string m_strMetaKey; - std::unordered_map> m_attrs; }; } diff --git a/meta/SaiObjectCollection.cpp b/meta/SaiObjectCollection.cpp index fb5a27596f24..f7465773e1f9 100644 --- a/meta/SaiObjectCollection.cpp +++ b/meta/SaiObjectCollection.cpp @@ -1,5 +1,4 @@ #include "SaiObjectCollection.h" -#include "Globals.h" #include "sai_serialize.h" @@ -12,26 +11,14 @@ void SaiObjectCollection::clear() m_objects.clear(); } -bool SaiObjectCollection::objectExists( - _In_ const std::string& key) const -{ - SWSS_LOG_ENTER(); - - bool exists = m_objects.find(key) != m_objects.end(); - - SWSS_LOG_DEBUG("%s %s", key.c_str(), exists ? "exists" : "missing"); - - return exists; -} - bool SaiObjectCollection::objectExists( _In_ const sai_object_meta_key_t& metaKey) const { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(metaKey); + bool exists = m_objects.find(metaKey) != m_objects.end(); - return objectExists(key); + return exists; } void SaiObjectCollection::createObject( @@ -41,16 +28,13 @@ void SaiObjectCollection::createObject( auto obj = std::make_shared(metaKey); - auto& key = obj->getStrMetaKey(); - - if (objectExists(key)) + if (objectExists(metaKey)) { - SWSS_LOG_THROW("FATAL: object %s already exists", key.c_str()); + SWSS_LOG_THROW("FATAL: object %s already exists", + sai_serialize_object_meta_key(metaKey).c_str()); } - SWSS_LOG_DEBUG("creating object %s", key.c_str()); - - m_objects[key] = obj; + m_objects[metaKey] = obj; } void SaiObjectCollection::removeObject( @@ -58,16 +42,13 @@ void SaiObjectCollection::removeObject( { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(metaKey); - - if (!objectExists(key)) + if (!objectExists(metaKey)) { - SWSS_LOG_THROW("FATAL: object %s doesn't exist", key.c_str()); + SWSS_LOG_THROW("FATAL: object %s doesn't exist", + sai_serialize_object_meta_key(metaKey).c_str()); } - SWSS_LOG_DEBUG("removing object %s", key.c_str()); - - m_objects.erase(key); + m_objects.erase(metaKey); } void SaiObjectCollection::setObjectAttr( @@ -77,37 +58,33 @@ void SaiObjectCollection::setObjectAttr( { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(metaKey); - - if (!objectExists(key)) + if (!objectExists(metaKey)) { - SWSS_LOG_THROW("FATAL: object %s doesn't exist", key.c_str()); + SWSS_LOG_THROW("FATAL: object %s doesn't exist", + sai_serialize_object_meta_key(metaKey).c_str()); } - META_LOG_DEBUG(md, "set attribute %d on %s", attr->id, key.c_str()); - - m_objects[key]->setAttr(&md, attr); + m_objects[metaKey]->setAttr(&md, attr); } std::shared_ptr SaiObjectCollection::getObjectAttr( - _In_ const sai_object_meta_key_t& meta_key, + _In_ const sai_object_meta_key_t& metaKey, _In_ sai_attr_id_t id) { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(meta_key); - /* * We can't throw if object don't exists, since we can call this function * on create API, and then previous object will not exists, of course we * should make exists check before. */ - auto it = m_objects.find(key); + auto it = m_objects.find(metaKey); if (it == m_objects.end()) { - SWSS_LOG_ERROR("object key %s not found", key.c_str()); + SWSS_LOG_ERROR("object key %s not found", + sai_serialize_object_meta_key(metaKey).c_str()); return nullptr; } @@ -136,21 +113,20 @@ std::shared_ptr SaiObjectCollection::getObject( { SWSS_LOG_ENTER(); - std::string key = sai_serialize_object_meta_key(metaKey); - - if (!objectExists(key)) + if (!objectExists(metaKey)) { - SWSS_LOG_THROW("FATAL: object %s doesn't exist", key.c_str()); + SWSS_LOG_THROW("FATAL: object %s doesn't exist", + sai_serialize_object_meta_key(metaKey).c_str()); } - return m_objects.at(key); + return m_objects.at(metaKey); } -std::vector SaiObjectCollection::getAllKeys() const +std::vector SaiObjectCollection::getAllKeys() const { SWSS_LOG_ENTER(); - std::vector vec; + std::vector vec; for (auto& it: m_objects) { diff --git a/meta/SaiObjectCollection.h b/meta/SaiObjectCollection.h index 8cec8449afd3..4abfaa3ab552 100644 --- a/meta/SaiObjectCollection.h +++ b/meta/SaiObjectCollection.h @@ -2,6 +2,7 @@ #include "SaiAttrWrapper.h" #include "SaiObject.h" +#include "MetaKeyHasher.h" #include #include @@ -26,9 +27,6 @@ namespace saimeta void clear(); - bool objectExists( - _In_ const std::string& key) const; - bool objectExists( _In_ const sai_object_meta_key_t& metaKey) const; @@ -44,7 +42,7 @@ namespace saimeta _In_ const sai_attribute_t *attr); std::shared_ptr getObjectAttr( - _In_ const sai_object_meta_key_t& meta_key, + _In_ const sai_object_meta_key_t& metaKey, _In_ sai_attr_id_t id); std::vector> getObjectAttributes( @@ -56,11 +54,11 @@ namespace saimeta std::shared_ptr getObject( _In_ const sai_object_meta_key_t& metaKey) const; - std::vector getAllKeys() const; + std::vector getAllKeys() const; private: - std::unordered_map> m_objects; + std::unordered_map, MetaKeyHasher, MetaKeyHasher> m_objects; }; } diff --git a/meta/tests.cpp b/meta/tests.cpp index d15a36f7d913..de2bbab9c448 100644 --- a/meta/tests.cpp +++ b/meta/tests.cpp @@ -541,9 +541,7 @@ void test_fdb_entry_remove() fdb_entry.mac_address[0] = 0x11; - sai_object_meta_key_t meta = { .objecttype = SAI_OBJECT_TYPE_FDB_ENTRY, .objectkey = { .key = { .fdb_entry = fdb_entry } } }; - - std::string key = sai_serialize_object_meta_key(meta); + sai_object_meta_key_t key = { .objecttype = SAI_OBJECT_TYPE_FDB_ENTRY, .objectkey = { .key = { .fdb_entry = fdb_entry } } }; META_ASSERT_TRUE(g_meta->objectExists(key)); @@ -1044,9 +1042,7 @@ void test_neighbor_entry_remove() neighbor_entry.rif_id = rif; - sai_object_meta_key_t meta = { .objecttype = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, .objectkey = { .key = { .neighbor_entry = neighbor_entry } } }; - - std::string key = sai_serialize_object_meta_key(meta); + sai_object_meta_key_t key = { .objecttype = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, .objectkey = { .key = { .neighbor_entry = neighbor_entry } } }; META_ASSERT_TRUE(g_meta->objectExists(key)); @@ -2007,9 +2003,7 @@ void test_route_entry_remove() route_entry.vr_id = vr; - sai_object_meta_key_t meta = { .objecttype = SAI_OBJECT_TYPE_ROUTE_ENTRY, .objectkey = { .key = { .route_entry = route_entry } } }; - - std::string key = sai_serialize_object_meta_key(meta); + sai_object_meta_key_t key = { .objecttype = SAI_OBJECT_TYPE_ROUTE_ENTRY, .objectkey = { .key = { .route_entry = route_entry } } }; META_ASSERT_TRUE(g_meta->objectExists(key)); @@ -3910,12 +3904,81 @@ void test_numbers() ASSERT_TRUE(u, 0x12345678); } +void test_bulk_route_entry_create() +{ + SWSS_LOG_ENTER(); + + clear_local(); + + int object_count = 1000; + + std::vector routes; + std::vector attr_counts; + std::vector attr_lists; + std::vector statuses(object_count); + + sai_object_id_t switch_id = create_switch(); + + sai_object_id_t vr = create_virtual_router(switch_id); + sai_object_id_t hop = create_next_hop(switch_id); + + sai_attribute_t attr; + + attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + attr.value.oid = hop; + + int n = 100; + + for (int i = 0; i < object_count * n; i++) + { + sai_route_entry_t re; + + memset(re.destination.mask.ip6, 0xff, sizeof(re.destination.mask.ip6)); + re.destination.addr_family = SAI_IP_ADDR_FAMILY_IPV4; + re.destination.addr.ip4 = htonl(0x0a00000f + i); + re.destination.mask.ip4 = htonl(0xffffff00); + re.vr_id = vr; + re.switch_id = switch_id; + + routes.push_back(re); + + attr_counts.push_back(1); + + // since we use the same attribute every where we can get away with this + + attr_lists.push_back(&attr); + } + + auto start = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < n; i++) + { + auto status = g_meta->bulkCreate( + object_count, + routes.data() + i * object_count, + attr_counts.data(), + attr_lists.data(), + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, + statuses.data()); + + ASSERT_TRUE(status, SAI_STATUS_SUCCESS); + } + + auto end = std::chrono::high_resolution_clock::now(); + auto time = end - start; + auto us = std::chrono::duration_cast(time); + + std::cout << "ms: " << (double)us.count()/1000 << " / " << n << "/" << object_count << std::endl; +} + int main() { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_INFO); SWSS_LOG_ENTER(); + test_bulk_route_entry_create(); + // serialize tests test_serialize_bool();