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:
|
- 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:
|
- Fix track durations:
|
||||||
Some tracks in my library are tagged with the wrong duration,
|
Some tracks in my library are tagged with the wrong duration,
|
||||||
so fix them as they are played.
|
so fix them as they are played.
|
||||||
|
|
|
@ -165,6 +165,31 @@ void db_remove(struct database *db, struct db_entry *item)
|
||||||
db_autosave(db);
|
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)
|
unsigned int db_actual_size(const struct database *db)
|
||||||
{
|
{
|
||||||
if (db->db_entries)
|
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. */
|
/* Called to remove an item from the database. */
|
||||||
void db_remove(struct database *, struct db_entry *);
|
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. */
|
/* Returns the database item at the requested index. */
|
||||||
struct db_entry *db_at(const struct database *, unsigned int);
|
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);
|
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);
|
db_deinit(&db);
|
||||||
g_assert_cmpuint(db.db_size, ==, 0);
|
g_assert_cmpuint(db.db_size, ==, 0);
|
||||||
g_assert_cmpuint(db_actual_size(&db), ==, 0);
|
g_assert_cmpuint(db_actual_size(&db), ==, 0);
|
||||||
|
|
Loading…
Reference in New Issue