From 85db2d670443089ed74d0ea389f2c1819542956e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 19 May 2021 07:59:42 +0200 Subject: [PATCH] db/proxy: split search into chunks to avoid exceeding the output buffer Closes https://github.com/MusicPlayerDaemon/MPD/issues/1130 --- NEWS | 1 + src/db/plugins/ProxyDatabasePlugin.cxx | 52 ++++++++++++++++++-------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 810d2e9ea..376674c24 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ ver 0.23 (not yet released) * database - proxy: require MPD 0.20 or later - proxy: require libmpdclient 2.11 or later + - proxy: split search into chunks to avoid exceeding the output buffer * output - pipewire: new plugin - snapcast: new plugin diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx index 71a3683f8..83f29f38f 100644 --- a/src/db/plugins/ProxyDatabasePlugin.cxx +++ b/src/db/plugins/ProxyDatabasePlugin.cxx @@ -825,26 +825,48 @@ try { const bool exact = selection.filter == nullptr || !selection.filter->HasFoldCase(); - if (!mpd_search_db_songs(connection, exact) || - !SendConstraints(connection, selection, selection.window) || - !mpd_search_commit(connection)) - ThrowError(connection); + /* request only this number of songs at a time to avoid + blowing the server's max_output_buffer_size limit */ + constexpr unsigned LIMIT = 4096; - while (auto *song = mpd_recv_song(connection)) { - AllocatedProxySong song2(song); + auto remaining_window = selection.window; - if (Match(selection.filter, song2)) { - try { - visit_song(song2); - } catch (...) { - mpd_response_finish(connection); - throw; + while (remaining_window.start < remaining_window.end) { + auto window = remaining_window; + if (window.end - window.start > LIMIT) + window.end = window.start + LIMIT; + + if (!mpd_search_db_songs(connection, exact) || + !SendConstraints(connection, selection, window) || + !mpd_search_commit(connection)) + ThrowError(connection); + + while (auto *song = mpd_recv_song(connection)) { + ++window.start; + + AllocatedProxySong song2(song); + + if (Match(selection.filter, song2)) { + try { + visit_song(song2); + } catch (...) { + mpd_response_finish(connection); + throw; + } } } - } - if (!mpd_response_finish(connection)) - ThrowError(connection); + if (!mpd_response_finish(connection)) + ThrowError(connection); + + if (window.start != window.end) + /* the other MPD has given us less than we + requested - this means there's no more + data */ + break; + + remaining_window.start = window.end; + } } catch (...) { if (connection != nullptr) mpd_search_cancel(connection);