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.
This commit is contained in:
Max Kellermann 2021-11-19 15:54:51 +01:00
parent ead5bcf048
commit b0c92e1a34

View File

@ -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;