From 050f3ebf4cba550664cd9f0ccebc4ffb9e828a9d Mon Sep 17 00:00:00 2001 From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com> Date: Thu, 9 Nov 2023 14:23:12 +0100 Subject: [PATCH] Improve MainDb::loadChatRooms by using a std::map instead of an std::list Increase timeout of Michelle's and focus's chat room deletion function simple_conference_base: wait for full state and then liblinphone tester timeout ms before checking volumes video_call_expected_fps_for_specified_bandwidth: increase number of iterations --- src/conference/conference.h | 32 ++++++ src/db/main-db.cpp | 147 ++++++++++++------------- src/db/main-db.h | 8 +- tester/audio_video_conference_tester.c | 33 +++++- tester/local_chat_tester.cpp | 14 +-- tester/video_quality_tester.c | 2 +- 6 files changed, 143 insertions(+), 93 deletions(-) diff --git a/src/conference/conference.h b/src/conference/conference.h index 8ca05371e4..22935b0b1c 100644 --- a/src/conference/conference.h +++ b/src/conference/conference.h @@ -64,6 +64,38 @@ class LINPHONE_PUBLIC Conference : public ConferenceInterface, public Conference friend class ServerGroupChatRoom; public: + struct ConferenceIdCompare { + bool operator()(const ConferenceId &lhs, const ConferenceId &rhs) const { + const auto &lhsRawPeerAddress = lhs.getPeerAddress(); + Address lhsPeerAddress = Address(); + if (lhsRawPeerAddress) { + lhsPeerAddress = lhsRawPeerAddress->getUriWithoutGruu(); + lhsPeerAddress.removeUriParam(Conference::SecurityModeParameter); + } + const auto &lhsRawLocalAddress = lhs.getLocalAddress(); + Address lhsLocalAddress = Address(); + if (lhsRawLocalAddress) { + lhsLocalAddress = lhsRawLocalAddress->getUriWithoutGruu(); + lhsLocalAddress.removeUriParam(Conference::SecurityModeParameter); + } + + const auto &rhsRawPeerAddress = rhs.getPeerAddress(); + Address rhsPeerAddress = Address(); + if (rhsRawPeerAddress) { + rhsPeerAddress = rhsRawPeerAddress->getUriWithoutGruu(); + rhsPeerAddress.removeUriParam(Conference::SecurityModeParameter); + } + const auto &rhsRawLocalAddress = rhs.getLocalAddress(); + Address rhsLocalAddress = Address(); + if (rhsRawLocalAddress) { + rhsLocalAddress = rhsRawLocalAddress->getUriWithoutGruu(); + rhsLocalAddress.removeUriParam(Conference::SecurityModeParameter); + } + + return (lhsPeerAddress < rhsPeerAddress) || + ((lhsPeerAddress == rhsPeerAddress) && (lhsLocalAddress < rhsLocalAddress)); + } + }; static constexpr int labelLength = 10; static const std::string SecurityModeParameter; ~Conference(); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index 1226486203..a92528638f 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -4909,91 +4909,74 @@ void MainDb::disableDisplayNotificationRequired(const std::shared_ptr<const Even // - set the creation time to the earliest one // - assign all events preceeding the latest creation time to the kept chatroom // - destroy the deleted chatroom from DB -void MainDb::addChatroomToList(list<shared_ptr<AbstractChatRoom>> &chatRooms, - const shared_ptr<AbstractChatRoom> chatRoom) const { +void MainDb::addChatroomToList( + std::map<ConferenceId, std::shared_ptr<AbstractChatRoom>, Conference::ConferenceIdCompare> &chatRoomsMap, + const shared_ptr<AbstractChatRoom> chatRoom) const { #ifdef HAVE_DB_STORAGE - L_D(); const auto chatRoomConferenceId = chatRoom->getConferenceId(); - const auto chatRoomIt = - std::find_if(chatRooms.cbegin(), chatRooms.cend(), [&chatRoomConferenceId](const auto &storedChatRoom) { - const auto &storedChatRoomConferenceId = storedChatRoom->getConferenceId(); - - const auto storedChatRoomConferenceIdPeerAddress = storedChatRoomConferenceId.getPeerAddress(); - const auto storedChatRoomConferenceIdPeerAddressWithoutGruu = - (storedChatRoomConferenceIdPeerAddress && storedChatRoomConferenceIdPeerAddress->isValid()) - ? storedChatRoomConferenceId.getPeerAddress()->getUriWithoutGruu() - : Address(); - const auto chatRoomConferenceIdPeerAddress = chatRoomConferenceId.getPeerAddress(); - const auto chatRoomConferenceIdPeerAddressWithoutGruu = - (chatRoomConferenceIdPeerAddress && chatRoomConferenceIdPeerAddress->isValid()) - ? chatRoomConferenceId.getPeerAddress()->getUriWithoutGruu() - : Address(); - - const auto storedChatRoomConferenceIdLocalAddress = storedChatRoomConferenceId.getLocalAddress(); - const auto storedChatRoomConferenceIdLocalAddressWithoutGruu = - (storedChatRoomConferenceIdLocalAddress && storedChatRoomConferenceIdLocalAddress->isValid()) - ? storedChatRoomConferenceId.getLocalAddress()->getUriWithoutGruu() - : Address(); - const auto chatRoomConferenceIdLocalAddress = chatRoomConferenceId.getLocalAddress(); - const auto chatRoomConferenceIdLocalAddressWithoutGruu = - (chatRoomConferenceIdLocalAddress && chatRoomConferenceIdLocalAddress->isValid()) - ? chatRoomConferenceId.getLocalAddress()->getUriWithoutGruu() - : Address(); - - return (storedChatRoomConferenceIdLocalAddressWithoutGruu == chatRoomConferenceIdLocalAddressWithoutGruu) && - (storedChatRoomConferenceIdPeerAddressWithoutGruu == chatRoomConferenceIdPeerAddressWithoutGruu); - }); shared_ptr<AbstractChatRoom> chatRoomToAdd = nullptr; - if (chatRoomIt == chatRooms.cend()) { + try { + auto storedChatRoom = chatRoomsMap.at(chatRoomConferenceId); + chatRoomToAdd = mergeChatRooms(chatRoom, storedChatRoom); + } catch (std::out_of_range &) { chatRoomToAdd = chatRoom; + } + chatRoomsMap.insert_or_assign(chatRoomConferenceId, chatRoomToAdd); +#endif +} + +shared_ptr<AbstractChatRoom> MainDb::mergeChatRooms(const shared_ptr<AbstractChatRoom> chatRoom1, + const shared_ptr<AbstractChatRoom> chatRoom2) const { +#ifdef HAVE_DB_STORAGE + L_D(); + shared_ptr<AbstractChatRoom> chatRoomToAdd = nullptr; + const auto chatRoom1ConferenceId = chatRoom1->getConferenceId(); + const auto chatRoom1CreationTime = chatRoom1->getCreationTime(); + const auto chatRoom2ConferenceId = chatRoom2->getConferenceId(); + const auto chatRoom2CreationTime = chatRoom2->getCreationTime(); + lInfo() << "Chat rooms with conference id " << chatRoom1ConferenceId << " and " << chatRoom2ConferenceId + << " will be merged as they have the same peer address"; + ConferenceId conferenceIdToAdd; + ConferenceId conferenceIdToRemove; + time_t creationTime = 0; + time_t creationTimeToDelete = 0; + // Update chatroom with the largest creation time and update its creation time with the lowest value. + if (chatRoom2CreationTime < chatRoom1CreationTime) { + chatRoomToAdd = chatRoom1; + creationTime = chatRoom2CreationTime; + creationTimeToDelete = chatRoom1CreationTime; + conferenceIdToAdd = chatRoom1ConferenceId; + conferenceIdToRemove = chatRoom2ConferenceId; } else { - auto storedChatRoom = (*chatRoomIt); - const auto storedChatRoomConferenceId = storedChatRoom->getConferenceId(); - const auto storedChatRoomCreationTime = storedChatRoom->getCreationTime(); - const auto chatRoomCreationTime = chatRoom->getCreationTime(); - lInfo() << "Chat rooms with conference id " << chatRoomConferenceId << " and " << storedChatRoomConferenceId - << " will be merged as they have the same peer address"; - chatRooms.erase(chatRoomIt); - ConferenceId conferenceIdToAdd; - ConferenceId conferenceIdToRemove; - time_t creationTime = 0; - time_t creationTimeToDelete = 0; - // Update chatroom with the largest creation time and update its creation time with the lowest value. - if (storedChatRoomCreationTime < chatRoomCreationTime) { - chatRoomToAdd = chatRoom; - creationTime = storedChatRoomCreationTime; - creationTimeToDelete = chatRoomCreationTime; - conferenceIdToAdd = chatRoomConferenceId; - conferenceIdToRemove = storedChatRoomConferenceId; - } else { - chatRoomToAdd = storedChatRoom; - creationTime = chatRoomCreationTime; - creationTimeToDelete = storedChatRoomCreationTime; - conferenceIdToAdd = storedChatRoomConferenceId; - conferenceIdToRemove = chatRoomConferenceId; - } - chatRoomToAdd->getPrivate()->setCreationTime(creationTime); - d->unreadChatMessageCountCache.insert(conferenceIdToAdd, - *d->unreadChatMessageCountCache[conferenceIdToAdd] + - *d->unreadChatMessageCountCache[conferenceIdToRemove]); - d->unreadChatMessageCountCache.insert(conferenceIdToRemove, 0); + chatRoomToAdd = chatRoom2; + creationTime = chatRoom1CreationTime; + creationTimeToDelete = chatRoom2CreationTime; + conferenceIdToAdd = chatRoom2ConferenceId; + conferenceIdToRemove = chatRoom1ConferenceId; + } + chatRoomToAdd->getPrivate()->setCreationTime(creationTime); + d->unreadChatMessageCountCache.insert(conferenceIdToAdd, *d->unreadChatMessageCountCache[conferenceIdToAdd] + + *d->unreadChatMessageCountCache[conferenceIdToRemove]); + d->unreadChatMessageCountCache.insert(conferenceIdToRemove, 0); - const long long &dbChatRoomToAddId = d->selectChatRoomId(conferenceIdToAdd); - const long long &dbChatRoomToRemoveId = d->selectChatRoomId(conferenceIdToRemove); + const long long &dbChatRoomToAddId = d->selectChatRoomId(conferenceIdToAdd); + const long long &dbChatRoomToRemoveId = d->selectChatRoomId(conferenceIdToRemove); - auto creationTimeToDeleteSoci = d->dbSession.getTimeWithSociIndicator(creationTimeToDelete); - soci::session *session = d->dbSession.getBackendSession(); - // Move conference event that occurred before the latest chatroom was created. - // Events such as chat messages are already stored in both chat rooms - *session << "UPDATE conference_event SET chat_room_id = :newChatRoomid WHERE event_id IN (SELECT " - "conference_event.event_id FROM conference_event, event WHERE event.id = conference_event.event_id " - "AND conference_event.chat_room_id = :chatRoomId AND event.creation_time < :creationTime)", - soci::use(dbChatRoomToAddId), soci::use(dbChatRoomToRemoveId), - soci::use(creationTimeToDeleteSoci.first, creationTimeToDeleteSoci.second); + auto creationTimeToDeleteSoci = d->dbSession.getTimeWithSociIndicator(creationTimeToDelete); + soci::session *session = d->dbSession.getBackendSession(); + // Move conference event that occurred before the latest chatroom was created. + // Events such as chat messages are already stored in both chat rooms + *session << "UPDATE conference_event SET chat_room_id = :newChatRoomid WHERE event_id IN (SELECT " + "conference_event.event_id FROM conference_event, event WHERE event.id = conference_event.event_id " + "AND conference_event.chat_room_id = :chatRoomId AND event.creation_time < :creationTime)", + soci::use(dbChatRoomToAddId), soci::use(dbChatRoomToRemoveId), + soci::use(creationTimeToDeleteSoci.first, creationTimeToDeleteSoci.second); + if (dbChatRoomToRemoveId != -1) { *session << "DELETE FROM chat_room WHERE id = :chatRoomId", soci::use(dbChatRoomToRemoveId); } - - chatRooms.push_back(chatRoomToAdd); + return chatRoomToAdd; +#else + return nullptr; #endif } @@ -5021,7 +5004,8 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const { return L_DB_TRANSACTION { L_D(); - list<shared_ptr<AbstractChatRoom>> chatRooms; + std::map<ConferenceId, std::shared_ptr<AbstractChatRoom>, Conference::ConferenceIdCompare> chatRoomsMap; + shared_ptr<Core> core = getCore(); bool serverMode = linphone_core_conference_server_enabled(core->getCCore()); @@ -5047,7 +5031,7 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const { shared_ptr<AbstractChatRoom> chatRoom = core->findChatRoom(conferenceId, false); if (chatRoom) { - chatRooms.push_back(chatRoom); + chatRoomsMap.insert(std::make_pair(conferenceId, chatRoom)); continue; } @@ -5181,11 +5165,16 @@ list<shared_ptr<AbstractChatRoom>> MainDb::getChatRooms() const { lDebug() << "Found chat room in DB: (peer=" << conferenceId.getPeerAddress()->toStringUriOnlyOrdered() << ", local=" << conferenceId.getLocalAddress()->toStringUriOnlyOrdered() << ")."; - addChatroomToList(chatRooms, chatRoom); + addChatroomToList(chatRoomsMap, chatRoom); } tr.commit(); + std::list<std::shared_ptr<AbstractChatRoom>> chatRooms; + for (const auto &[conferenceId, chatRoom] : chatRoomsMap) { + chatRooms.push_back(chatRoom); + } + return chatRooms; }; #else diff --git a/src/db/main-db.h b/src/db/main-db.h index e88fc8bebf..e601b03531 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -33,6 +33,7 @@ #include "chat/chat-message/chat-message.h" #include "conference/conference-id.h" #include "conference/conference-info.h" +#include "conference/conference.h" #include "core/core-accessor.h" // ============================================================================= @@ -251,8 +252,11 @@ private: L_DISABLE_COPY(MainDb); void initCleanup(); - void addChatroomToList(std::list<std::shared_ptr<AbstractChatRoom>> &chatRooms, - const std::shared_ptr<AbstractChatRoom> chatRoom) const; + void addChatroomToList( + std::map<ConferenceId, std::shared_ptr<AbstractChatRoom>, Conference::ConferenceIdCompare> &chatRoomsMap, + const std::shared_ptr<AbstractChatRoom> chatRoom) const; + std::shared_ptr<AbstractChatRoom> mergeChatRooms(const std::shared_ptr<AbstractChatRoom> chatRoom1, + const std::shared_ptr<AbstractChatRoom> chatRoom2) const; }; LINPHONE_END_NAMESPACE diff --git a/tester/audio_video_conference_tester.c b/tester/audio_video_conference_tester.c index f34da0c012..72439e3aab 100644 --- a/tester/audio_video_conference_tester.c +++ b/tester/audio_video_conference_tester.c @@ -590,8 +590,39 @@ static void simple_conference_base(LinphoneCoreManager *marie, BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, initial_marie_stat.number_of_LinphoneCallStreamsRunning + 2, 3000)); + bool_t marie_event_log_enabled = + linphone_config_get_bool(linphone_core_get_config(marie->lc), "misc", "conference_event_log_enabled", TRUE); + if (marie_event_log_enabled) { + bool_t marie_conference_server = linphone_core_conference_server_enabled(marie->lc); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneSubscriptionActive, + (initial_marie_stat.number_of_LinphoneSubscriptionActive + 1), 5000)); + if (!marie_conference_server) { + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_NotifyFullStateReceived, + (initial_marie_stat.number_of_NotifyFullStateReceived + 1), + liblinphone_tester_sip_timeout)); + } + } + bool_t laure_event_log_enabled = + linphone_config_get_bool(linphone_core_get_config(laure->lc), "misc", "conference_event_log_enabled", TRUE); + if (laure_event_log_enabled && marie_event_log_enabled) { + BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_LinphoneSubscriptionActive, + (initial_laure_stat.number_of_LinphoneSubscriptionActive + 1), 5000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &laure->stat.number_of_NotifyFullStateReceived, + (initial_laure_stat.number_of_NotifyFullStateReceived + 1), + liblinphone_tester_sip_timeout)); + } + bool_t pauline_event_log_enabled = + linphone_config_get_bool(linphone_core_get_config(pauline->lc), "misc", "conference_event_log_enabled", TRUE); + if (pauline_event_log_enabled && marie_event_log_enabled) { + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneSubscriptionActive, + (initial_pauline_stat.number_of_LinphoneSubscriptionActive + 1), 5000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_NotifyFullStateReceived, + (initial_pauline_stat.number_of_NotifyFullStateReceived + 1), + liblinphone_tester_sip_timeout)); + } + // wait a bit to ensure that should NOTIFYs be sent, they reach their destination - wait_for_list(lcs, NULL, 0, 3000); + wait_for_list(lcs, NULL, 0, liblinphone_tester_sip_timeout); // Check that laure received volumes from other participant's devices LinphoneCall *laure_call = linphone_core_get_current_call(laure->lc); diff --git a/tester/local_chat_tester.cpp b/tester/local_chat_tester.cpp index 9239f51aa0..f022105b54 100644 --- a/tester/local_chat_tester.cpp +++ b/tester/local_chat_tester.cpp @@ -2727,9 +2727,6 @@ static void group_chat_room_with_duplications(void) { // wait bit more to detect side effect if any CoreManagerAssert({focus, marie, pauline, michelle, laure}).waitUntil(chrono::seconds(5), [] { return false; }); - account = linphone_core_get_default_account(laure.getLc()); - LinphoneAddress *oldLaureDeviceAddress = linphone_address_clone(linphone_account_get_contact_address(account)); - ms_message("%s reinitializes its core", linphone_core_get_identity(laure.getLc())); coresList = bctbx_list_remove(coresList, laure.getLc()); linphone_core_manager_reinit(laure.getCMgr()); @@ -2761,12 +2758,9 @@ static void group_chat_room_with_duplications(void) { // Notify chat room that a participant has registered bctbx_list_t *devices = NULL; bctbx_list_t *specs = linphone_core_get_linphone_specs_list(laure.getLc()); - LinphoneParticipantDeviceIdentity *identity = - linphone_factory_create_participant_device_identity(linphone_factory_get(), oldLaureDeviceAddress, ""); - linphone_participant_device_identity_set_capability_descriptor_2(identity, specs); - devices = bctbx_list_append(devices, identity); - identity = linphone_factory_create_participant_device_identity(linphone_factory_get(), laureDeviceAddress, ""); + LinphoneParticipantDeviceIdentity *identity = + linphone_factory_create_participant_device_identity(linphone_factory_get(), laureDeviceAddress, ""); linphone_participant_device_identity_set_capability_descriptor_2(identity, specs); devices = bctbx_list_append(devices, identity); bctbx_list_free_with_data(specs, ms_free); @@ -2830,7 +2824,7 @@ static void group_chat_room_with_duplications(void) { } BC_ASSERT_TRUE(wait_for_list(coresList, &michelle.getStats().number_of_LinphoneConferenceStateDeleted, michelle_stat.number_of_LinphoneConferenceStateDeleted + nbChatrooms, - liblinphone_tester_sip_timeout)); + 3 * liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &marie.getStats().number_of_participants_removed, marie_stat.number_of_participants_removed + nbChatrooms, liblinphone_tester_sip_timeout)); @@ -2965,7 +2959,7 @@ static void group_chat_room_with_duplications(void) { // wait until chatroom is deleted server side BC_ASSERT_TRUE( - CoreManagerAssert({focus, marie, pauline, michelle, laure}).waitUntil(chrono::seconds(90), [&focus] { + CoreManagerAssert({focus, marie, pauline, michelle, laure}).waitUntil(chrono::seconds(120), [&focus] { return focus.getCore().getChatRooms().size() == 0; })); diff --git a/tester/video_quality_tester.c b/tester/video_quality_tester.c index 1faff5a19a..47a389169b 100644 --- a/tester/video_quality_tester.c +++ b/tester/video_quality_tester.c @@ -279,7 +279,7 @@ static void video_call_expected_fps_for_specified_bandwidth(int bandwidth, int e /*wait some time until the target fps is reached. Indeed the bandwidth measurement may take several iterations to converge to a value big enough to allow mediastreamer2 to switch to the high fps profile*/ - for (count = 0; count < 3; count++) { + for (count = 0; count < 10; count++) { /*wait for at least the first TMMBR to arrive*/ BC_ASSERT_TRUE( wait_for_until(marie->lc, pauline->lc, &marie->stat.last_tmmbr_value_received, 1, 10000)); -- GitLab