core/database: Add support for defragmenting databases
Removing items from the database leaves a NULL pointer "hole" that is never filled in. This doesn't affect correctness, but it could be wasteful as items are added and removed. This patch adds a function to defragment the database without changing the order of items. Implements #66: Add support for rebalancing databases Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
parent
8d9139aea5
commit
86d7fe43ed
9
TODO
9
TODO
|
@ -12,15 +12,6 @@ Future work:
|
|||
|
||||
- Save a user's playlist as a group:
|
||||
|
||||
- Library defragment:
|
||||
Ocarina 6.0 will leave holes in the library when tracks are
|
||||
deleted, potentially leading to fragmentation and larger-than-
|
||||
needed file sizes. A "defragment" utility can be created to
|
||||
clean up unused slots.
|
||||
|
||||
To help with fixing groups, a mapping of (old values) ->
|
||||
(new values) should be kept.
|
||||
|
||||
- Fix track durations:
|
||||
Some tracks in my library are tagged with the wrong duration,
|
||||
so fix them as they are played.
|
||||
|
|
|
@ -165,6 +165,31 @@ void db_remove(struct database *db, struct db_entry *item)
|
|||
db_autosave(db);
|
||||
}
|
||||
|
||||
bool db_defrag(struct database *db)
|
||||
{
|
||||
struct db_entry *dbe;
|
||||
unsigned int i, cur;
|
||||
|
||||
if (db->db_size == db_actual_size(db))
|
||||
return false;
|
||||
|
||||
for (cur = 0, i = 1; cur < db->db_size; cur++) {
|
||||
if (DB_ENTRY_AT(db, cur))
|
||||
continue;
|
||||
while (i <= cur || !DB_ENTRY_AT(db, i))
|
||||
i++;
|
||||
|
||||
dbe = DB_ENTRY_AT(db, i);
|
||||
g_ptr_array_index(db->db_entries, i) = NULL;
|
||||
g_ptr_array_index(db->db_entries, cur) = dbe;
|
||||
dbe->dbe_index = cur;
|
||||
}
|
||||
|
||||
g_ptr_array_set_size(db->db_entries, db->db_size);
|
||||
db_autosave(db);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int db_actual_size(const struct database *db)
|
||||
{
|
||||
if (db->db_entries)
|
||||
|
|
|
@ -123,6 +123,12 @@ struct db_entry *db_insert(struct database *, const gchar *);
|
|||
/* Called to remove an item from the database. */
|
||||
void db_remove(struct database *, struct db_entry *);
|
||||
|
||||
/*
|
||||
* Called to shrink the database by removing any NULL pointers without
|
||||
* changing the order of items in the database.
|
||||
* Returns true if the database has been modified.
|
||||
*/
|
||||
bool db_defrag(struct database *);
|
||||
|
||||
/* Returns the database item at the requested index. */
|
||||
struct db_entry *db_at(const struct database *, unsigned int);
|
||||
|
|
|
@ -219,6 +219,19 @@ static void test_database(gconstpointer arg)
|
|||
}
|
||||
g_assert_cmpuint(i, ==, N + 1);
|
||||
|
||||
/* db_defrag(): Remove all NULL pointers */
|
||||
i = 0;
|
||||
g_assert_true(db_defrag(&db));
|
||||
g_assert_cmpuint(db.db_size, ==, N / 2);
|
||||
g_assert_cmpuint(db_actual_size(&db), ==, N / 2);
|
||||
db_for_each(dbe, next, &db) {
|
||||
g_assert_nonnull(dbe);
|
||||
g_assert_cmpuint(INT_ENTRY(dbe)->ie_val, ==, (i * 2) + 1);
|
||||
g_assert(dbe == db_at(&db, i));
|
||||
i++;
|
||||
}
|
||||
g_assert_false(db_defrag(&db));
|
||||
|
||||
db_deinit(&db);
|
||||
g_assert_cmpuint(db.db_size, ==, 0);
|
||||
g_assert_cmpuint(db_actual_size(&db), ==, 0);
|
||||
|
|
Loading…
Reference in New Issue