channelstorage_cpp_map_name_id.cc: Refactor iterators for thread-safety.

The fact that deleting an object from a map invalidates any iterator
that happens to currently point to that object was overlooked in the initial
implementation.  Unfortunately, there's no way to detect that an iterator
has been invalidated so the result was an occasional SEGV triggered by modules
like app_chanspy that opens an iterator and can keep it open for a long period
of time.  The new implementation doesn't keep the underlying C++ iterator
open across calls to ast_channel_iterator_next() and uses a read lock
on the map to ensure that, even for the few microseconds we use the
iterator, another thread can't delete a channel from under it.  Even with
this change, the iterators are still WAY faster than the ao2_legacy
storage driver.

Full details about the new implementation are located in the comments for
iterator_next() in channelstorage_cpp_map_name_id.cc.

Resolves: #1309
This commit is contained in:
George Joseph
2025-07-30 06:39:49 -06:00
committed by github-actions[bot]
parent 22d405e900
commit baa73b6b12
2 changed files with 199 additions and 137 deletions

View File

@@ -277,76 +277,6 @@ static void *test_storage_thread(void *data)
elapsed = ast_tvdiff_us(end, start);
ast_test_status_update(test, "%*s: %8ld\n", collen, "by context/exten", elapsed);
#if 0
start = ast_tvnow();
for (i = 0; i < CHANNEL_COUNT; i++) {
sprintf(search1, "TestChannel-%ld-%04d-something", rand, i);
mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_or_uniqueid, search1);
ast_test_validate_cleanup(test, mock_channel, res, done);
CHANNELSTORAGE_API(storage_instance, wrlock);
sprintf(mock_channel->context, "TestXXContext-%ld-%04d", rand, i);
sprintf(search1, "TestContext-%ld-%04d", rand, i);
rc = CHANNELSTORAGE_API(storage_instance, update, mock_channel,
AST_CHANNELSTORAGE_UPDATE_CONTEXT, search1, mock_channel->context, 0);
ast_test_validate_cleanup(test, rc == 0, res, done);
sprintf(mock_channel->exten, "TestXXExten-%ld-%04d", rand, i);
sprintf(search2, "TestExten-%ld-%04d", rand, i);
rc = CHANNELSTORAGE_API(storage_instance, update, mock_channel,
AST_CHANNELSTORAGE_UPDATE_EXTEN, search2, mock_channel->exten, 0);
CHANNELSTORAGE_API(storage_instance, unlock);
ast_test_validate_cleanup(test, rc == 0, res, done);
ast_channel_unref(mock_channel);
}
end = ast_tvnow();
elapsed = ast_tvdiff_us(end, start);
ast_test_status_update(test, "%*s: %8ld\n", collen, "update", elapsed);
start = ast_tvnow();
for (i = 0; i < CHANNEL_COUNT; i++) {
sprintf(search1, "TestXXContext-%ld-%04d", rand, i);
sprintf(search2, "TestXXExten-%ld-%04d", rand, i);
mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_exten, search2, search1);
ast_test_validate_cleanup(test, mock_channel, res, done);
ast_channel_unref(mock_channel);
}
end = ast_tvnow();
elapsed = ast_tvdiff_us(end, start);
ast_test_status_update(test, "%*s: %8ld\n", collen, "by context/exten2", elapsed);
start = ast_tvnow();
for (i = 0; i < CHANNEL_COUNT; i++) {
sprintf(search1, "TestChannel-%ld-%04d-something", rand, i);
mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_or_uniqueid, search1);
ast_test_validate_cleanup(test, mock_channel, res, done);
sprintf(search2, "TestXXChannel-%ld-%04d", rand, i);
rc = CHANNELSTORAGE_API(storage_instance, update, mock_channel,
AST_CHANNELSTORAGE_UPDATE_NAME, search1, search2, 1);
ast_channel_unref(mock_channel);
ast_test_validate_cleanup(test, rc == 0, res, done);
}
end = ast_tvnow();
elapsed = ast_tvdiff_us(end, start);
ast_test_status_update(test, "%*s: %8ld\n", collen, "change name", elapsed);
start = ast_tvnow();
for (i = 0; i < CHANNEL_COUNT; i++) {
sprintf(search1, "TestXXChannel-%ld-%04d", rand, i);
mock_channel = CHANNELSTORAGE_API(storage_instance, get_by_name_or_uniqueid, search1);
ast_test_validate_cleanup_custom(test, mock_channel, res, done,"Channel %s not found\n", search1);
ast_channel_unref(mock_channel);
}
end = ast_tvnow();
elapsed = ast_tvdiff_us(end, start);
ast_test_status_update(test, "%*s: %8ld\n", collen, "by name exact2", elapsed);
#endif
i = 0;
start = ast_tvnow();
iter = CHANNELSTORAGE_API(storage_instance, iterator_all_new);