From b0c92e1a348e4fb736e6b59166ba929a86fdf3a5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 19 Nov 2021 15:54:51 +0100 Subject: [PATCH] queue/IdTable: lazy-initialize the "data" array With large "max_playlist_length" settings, the "data" array can be very large, and initializing it during MPD startup causes page faults, resulting in allocation of physical RAM. This commit postpones the initialization until the queue is really large, to avoid wasting memory. --- src/queue/IdTable.hxx | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/queue/IdTable.hxx b/src/queue/IdTable.hxx index 7c55869ff..93fae667a 100644 --- a/src/queue/IdTable.hxx +++ b/src/queue/IdTable.hxx @@ -31,6 +31,15 @@ class IdTable { const unsigned size; + /** + * How many members of "data" are initialized? + * + * The initial value is 1 and not 0 because the first element + * of the array is never used, because 0 is not a valid song + * id. + */ + unsigned initialized = 1; + unsigned next; int *const data; @@ -38,7 +47,6 @@ class IdTable { public: IdTable(unsigned _size) noexcept :size(_size), next(1), data(new int[size]) { - std::fill_n(data, size, -1); } ~IdTable() noexcept { @@ -49,14 +57,14 @@ public: IdTable &operator=(const IdTable &) = delete; int IdToPosition(unsigned id) const noexcept { - return id < size + return id < initialized ? data[id] : -1; } unsigned GenerateId() noexcept { assert(next > 0); - assert(next < size); + assert(next <= initialized); while (true) { unsigned id = next; @@ -65,6 +73,15 @@ public: if (next == size) next = 1; + if (id == initialized) { + /* the caller will initialize + data[id] */ + ++initialized; + return id; + } + + assert(id < initialized); + if (data[id] < 0) return id; } @@ -72,19 +89,20 @@ public: unsigned Insert(unsigned position) noexcept { unsigned id = GenerateId(); + assert(id < initialized); data[id] = position; return id; } void Move(unsigned id, unsigned position) noexcept { - assert(id < size); + assert(id < initialized); assert(data[id] >= 0); data[id] = position; } void Erase(unsigned id) noexcept { - assert(id < size); + assert(id < initialized); assert(data[id] >= 0); data[id] = -1;