Commit 3b8532f3 authored by Max Kellermann's avatar Max Kellermann

DatabasePlugin: add method ReturnSong()

Allow the plugin to allocate the GetSong() return value.
parent f45616e5
...@@ -132,6 +132,15 @@ db_get_song(const char *file) ...@@ -132,6 +132,15 @@ db_get_song(const char *file)
return db->GetSong(file, NULL); return db->GetSong(file, NULL);
} }
void
db_return_song(struct song *song)
{
assert(db != nullptr);
assert(song != nullptr);
db->ReturnSong(song);
}
bool bool
db_save(GError **error_r) db_save(GError **error_r)
{ {
......
...@@ -85,7 +85,8 @@ public: ...@@ -85,7 +85,8 @@ public:
virtual void Close() {} virtual void Close() {}
/** /**
* Look up a song (including tag data) in the database. * Look up a song (including tag data) in the database. When
* you don't need this anymore, call ReturnSong().
* *
* @param uri_utf8 the URI of the song within the music * @param uri_utf8 the URI of the song within the music
* directory (UTF-8) * directory (UTF-8)
...@@ -94,6 +95,12 @@ public: ...@@ -94,6 +95,12 @@ public:
GError **error_r) const = 0; GError **error_r) const = 0;
/** /**
* Mark the song object as "unused". Call this on objects
* returned by GetSong().
*/
virtual void ReturnSong(struct song *song) const = 0;
/**
* Visit the selected entities. * Visit the selected entities.
*/ */
virtual bool Visit(const DatabaseSelection &selection, virtual bool Visit(const DatabaseSelection &selection,
......
...@@ -1326,6 +1326,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) ...@@ -1326,6 +1326,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
} }
value = sticker_song_get_value(song, argv[4]); value = sticker_song_get_value(song, argv[4]);
db_return_song(song);
if (value == NULL) { if (value == NULL) {
command_error(client, ACK_ERROR_NO_EXIST, command_error(client, ACK_ERROR_NO_EXIST,
"no such sticker"); "no such sticker");
...@@ -1349,6 +1350,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) ...@@ -1349,6 +1350,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
} }
sticker = sticker_song_get(song); sticker = sticker_song_get(song);
db_return_song(song);
if (sticker) { if (sticker) {
sticker_print(client, sticker); sticker_print(client, sticker);
sticker_free(sticker); sticker_free(sticker);
...@@ -1368,6 +1370,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) ...@@ -1368,6 +1370,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
} }
ret = sticker_song_set_value(song, argv[4], argv[5]); ret = sticker_song_set_value(song, argv[4], argv[5]);
db_return_song(song);
if (!ret) { if (!ret) {
command_error(client, ACK_ERROR_SYSTEM, command_error(client, ACK_ERROR_SYSTEM,
"failed to set sticker value"); "failed to set sticker value");
...@@ -1391,6 +1394,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) ...@@ -1391,6 +1394,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
ret = argc == 4 ret = argc == 4
? sticker_song_delete(song) ? sticker_song_delete(song)
: sticker_song_delete_value(song, argv[4]); : sticker_song_delete_value(song, argv[4]);
db_return_song(song);
if (!ret) { if (!ret) {
command_error(client, ACK_ERROR_SYSTEM, command_error(client, ACK_ERROR_SYSTEM,
"no such sticker"); "no such sticker");
......
...@@ -74,6 +74,10 @@ gcc_pure ...@@ -74,6 +74,10 @@ gcc_pure
struct song * struct song *
db_get_song(const char *file); db_get_song(const char *file);
gcc_nonnull(1)
void
db_return_song(struct song *song);
/** /**
* May only be used if db_is_simple() returns true. * May only be used if db_is_simple() returns true.
*/ */
......
...@@ -56,6 +56,8 @@ public: ...@@ -56,6 +56,8 @@ public:
virtual void Close() override; virtual void Close() override;
virtual struct song *GetSong(const char *uri_utf8, virtual struct song *GetSong(const char *uri_utf8,
GError **error_r) const override; GError **error_r) const override;
virtual void ReturnSong(struct song *song) const;
virtual bool Visit(const DatabaseSelection &selection, virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory, VisitDirectory visit_directory,
VisitSong visit_song, VisitSong visit_song,
...@@ -191,6 +193,16 @@ ProxyDatabase::GetSong(const char *uri, GError **error_r) const ...@@ -191,6 +193,16 @@ ProxyDatabase::GetSong(const char *uri, GError **error_r) const
return nullptr; return nullptr;
} }
void
ProxyDatabase::ReturnSong(struct song *song) const
{
assert(song != nullptr);
assert(song_in_database(song));
assert(song_is_detached(song));
song_free(song);
}
static bool static bool
Visit(struct mpd_connection *connection, const char *uri, Visit(struct mpd_connection *connection, const char *uri,
bool recursive, VisitDirectory visit_directory, VisitSong visit_song, bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
......
...@@ -184,6 +184,10 @@ SimpleDatabase::Open(GError **error_r) ...@@ -184,6 +184,10 @@ SimpleDatabase::Open(GError **error_r)
root = directory_new_root(); root = directory_new_root();
mtime = 0; mtime = 0;
#ifndef NDEBUG
borrowed_song_count = 0;
#endif
GError *error = NULL; GError *error = NULL;
if (!Load(&error)) { if (!Load(&error)) {
directory_free(root); directory_free(root);
...@@ -204,6 +208,7 @@ void ...@@ -204,6 +208,7 @@ void
SimpleDatabase::Close() SimpleDatabase::Close()
{ {
assert(root != NULL); assert(root != NULL);
assert(borrowed_song_count == 0);
directory_free(root); directory_free(root);
} }
...@@ -219,10 +224,25 @@ SimpleDatabase::GetSong(const char *uri, GError **error_r) const ...@@ -219,10 +224,25 @@ SimpleDatabase::GetSong(const char *uri, GError **error_r) const
if (song == NULL) if (song == NULL)
g_set_error(error_r, db_quark(), DB_NOT_FOUND, g_set_error(error_r, db_quark(), DB_NOT_FOUND,
"No such song: %s", uri); "No such song: %s", uri);
#ifndef NDEBUG
else
++const_cast<unsigned &>(borrowed_song_count);
#endif
return song; return song;
} }
void
SimpleDatabase::ReturnSong(gcc_unused struct song *song) const
{
assert(song != nullptr);
#ifndef NDEBUG
assert(borrowed_song_count > 0);
--const_cast<unsigned &>(borrowed_song_count);
#endif
}
G_GNUC_PURE G_GNUC_PURE
const struct directory * const struct directory *
SimpleDatabase::LookupDirectory(const char *uri) const SimpleDatabase::LookupDirectory(const char *uri) const
......
...@@ -38,6 +38,10 @@ class SimpleDatabase : public Database { ...@@ -38,6 +38,10 @@ class SimpleDatabase : public Database {
time_t mtime; time_t mtime;
#ifndef NDEBUG
unsigned borrowed_song_count;
#endif
public: public:
gcc_pure gcc_pure
struct directory *GetRoot() { struct directory *GetRoot() {
...@@ -61,6 +65,8 @@ public: ...@@ -61,6 +65,8 @@ public:
virtual struct song *GetSong(const char *uri_utf8, virtual struct song *GetSong(const char *uri_utf8,
GError **error_r) const override; GError **error_r) const override;
virtual void ReturnSong(struct song *song) const;
virtual bool Visit(const DatabaseSelection &selection, virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory, VisitDirectory visit_directory,
VisitSong visit_song, VisitSong visit_song,
......
...@@ -128,7 +128,12 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc, ...@@ -128,7 +128,12 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc,
if (song == NULL) if (song == NULL)
return PLAYLIST_RESULT_NO_SUCH_SONG; return PLAYLIST_RESULT_NO_SUCH_SONG;
return playlist_append_song(playlist, pc, song, added_id); enum playlist_result result =
playlist_append_song(playlist, pc, song, added_id);
if (song_in_database(song))
db_return_song(song);
return result;
} }
enum playlist_result enum playlist_result
......
...@@ -127,6 +127,7 @@ spl_print(struct client *client, const char *name_utf8, bool detail, ...@@ -127,6 +127,7 @@ spl_print(struct client *client, const char *name_utf8, bool detail,
struct song *song = db_get_song(temp); struct song *song = db_get_song(temp);
if (song) { if (song) {
song_print_info(client, song); song_print_info(client, song);
db_return_song(song);
wrote = true; wrote = true;
} }
} }
...@@ -157,8 +158,7 @@ playlist_provider_print(struct client *client, const char *uri, ...@@ -157,8 +158,7 @@ playlist_provider_print(struct client *client, const char *uri,
else else
song_print_uri(client, song); song_print_uri(client, song);
if (!song_in_database(song) || song_is_detached(song)) song_free(song);
song_free(song);
} }
g_free(base_uri); g_free(base_uri);
......
...@@ -41,8 +41,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, ...@@ -41,8 +41,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
++i) { ++i) {
if (i < start_index) { if (i < start_index) {
/* skip songs before the start index */ /* skip songs before the start index */
if (!song_in_database(song)) song_free(song);
song_free(song);
continue; continue;
} }
...@@ -51,9 +50,8 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, ...@@ -51,9 +50,8 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source,
continue; continue;
result = playlist_append_song(dest, pc, song, NULL); result = playlist_append_song(dest, pc, song, NULL);
song_free(song);
if (result != PLAYLIST_RESULT_SUCCESS) { if (result != PLAYLIST_RESULT_SUCCESS) {
if (!song_in_database(song))
song_free(song);
g_free(base_uri); g_free(base_uri);
return result; return result;
} }
......
...@@ -79,9 +79,7 @@ apply_song_metadata(struct song *dest, const struct song *src) ...@@ -79,9 +79,7 @@ apply_song_metadata(struct song *dest, const struct song *src)
(e.g. last track on a CUE file); fix it up here */ (e.g. last track on a CUE file); fix it up here */
tmp->tag->time = dest->tag->time - src->start_ms / 1000; tmp->tag->time = dest->tag->time - src->start_ms / 1000;
if (!song_in_database(dest)) song_free(dest);
song_free(dest);
return tmp; return tmp;
} }
...@@ -97,10 +95,13 @@ playlist_check_load_song(const struct song *song, const char *uri, bool secure) ...@@ -97,10 +95,13 @@ playlist_check_load_song(const struct song *song, const char *uri, bool secure)
if (dest == NULL) if (dest == NULL)
return NULL; return NULL;
} else { } else {
dest = db_get_song(uri); struct song *tmp = db_get_song(uri);
if (dest == NULL) if (tmp == NULL)
/* not found in database */ /* not found in database */
return NULL; return NULL;
dest = song_dup_detached(tmp);
db_return_song(tmp);
} }
return apply_song_metadata(dest, song); return apply_song_metadata(dest, song);
......
...@@ -103,4 +103,7 @@ queue_load_song(FILE *fp, GString *buffer, const char *line, ...@@ -103,4 +103,7 @@ queue_load_song(FILE *fp, GString *buffer, const char *line,
} }
queue_append(queue, song); queue_append(queue, song);
if (song_in_database(song))
db_return_song(song);
} }
...@@ -496,7 +496,9 @@ spl_append_uri(const char *url, const char *utf8file, GError **error_r) ...@@ -496,7 +496,9 @@ spl_append_uri(const char *url, const char *utf8file, GError **error_r)
return false; return false;
} }
return spl_append_song(utf8file, song, error_r); bool success = spl_append_song(utf8file, song, error_r);
db_return_song(song);
return success;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment