DatabasePlugin: add method ReturnSong()
Allow the plugin to allocate the GetSong() return value.
This commit is contained in:
		| @@ -132,6 +132,15 @@ db_get_song(const char *file) | ||||
| 	return db->GetSong(file, NULL); | ||||
| } | ||||
|  | ||||
| void | ||||
| db_return_song(struct song *song) | ||||
| { | ||||
| 	assert(db != nullptr); | ||||
| 	assert(song != nullptr); | ||||
|  | ||||
| 	db->ReturnSong(song); | ||||
| } | ||||
|  | ||||
| bool | ||||
| db_save(GError **error_r) | ||||
| { | ||||
|   | ||||
| @@ -85,7 +85,8 @@ public: | ||||
| 	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 | ||||
| 	 * directory (UTF-8) | ||||
| @@ -93,6 +94,12 @@ public: | ||||
| 	virtual struct song *GetSong(const char *uri_utf8, | ||||
| 				     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. | ||||
| 	 */ | ||||
|   | ||||
| @@ -1326,6 +1326,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) | ||||
| 		} | ||||
|  | ||||
| 		value = sticker_song_get_value(song, argv[4]); | ||||
| 		db_return_song(song); | ||||
| 		if (value == NULL) { | ||||
| 			command_error(client, ACK_ERROR_NO_EXIST, | ||||
| 				      "no such sticker"); | ||||
| @@ -1349,6 +1350,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) | ||||
| 		} | ||||
|  | ||||
| 		sticker = sticker_song_get(song); | ||||
| 		db_return_song(song); | ||||
| 		if (sticker) { | ||||
| 			sticker_print(client, sticker); | ||||
| 			sticker_free(sticker); | ||||
| @@ -1368,6 +1370,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) | ||||
| 		} | ||||
|  | ||||
| 		ret = sticker_song_set_value(song, argv[4], argv[5]); | ||||
| 		db_return_song(song); | ||||
| 		if (!ret) { | ||||
| 			command_error(client, ACK_ERROR_SYSTEM, | ||||
| 				      "failed to set sticker value"); | ||||
| @@ -1391,6 +1394,7 @@ handle_sticker_song(struct client *client, int argc, char *argv[]) | ||||
| 		ret = argc == 4 | ||||
| 			? sticker_song_delete(song) | ||||
| 			: sticker_song_delete_value(song, argv[4]); | ||||
| 		db_return_song(song); | ||||
| 		if (!ret) { | ||||
| 			command_error(client, ACK_ERROR_SYSTEM, | ||||
| 				      "no such sticker"); | ||||
|   | ||||
| @@ -74,6 +74,10 @@ gcc_pure | ||||
| struct song * | ||||
| 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. | ||||
|  */ | ||||
|   | ||||
| @@ -56,6 +56,8 @@ public: | ||||
| 	virtual void Close() override; | ||||
| 	virtual struct song *GetSong(const char *uri_utf8, | ||||
| 				     GError **error_r) const override; | ||||
| 	virtual void ReturnSong(struct song *song) const; | ||||
|  | ||||
| 	virtual bool Visit(const DatabaseSelection &selection, | ||||
| 			   VisitDirectory visit_directory, | ||||
| 			   VisitSong visit_song, | ||||
| @@ -191,6 +193,16 @@ ProxyDatabase::GetSong(const char *uri, GError **error_r) const | ||||
| 	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 | ||||
| Visit(struct mpd_connection *connection, const char *uri, | ||||
|       bool recursive, VisitDirectory visit_directory, VisitSong visit_song, | ||||
|   | ||||
| @@ -184,6 +184,10 @@ SimpleDatabase::Open(GError **error_r) | ||||
| 	root = directory_new_root(); | ||||
| 	mtime = 0; | ||||
|  | ||||
| #ifndef NDEBUG | ||||
| 	borrowed_song_count = 0; | ||||
| #endif | ||||
|  | ||||
| 	GError *error = NULL; | ||||
| 	if (!Load(&error)) { | ||||
| 		directory_free(root); | ||||
| @@ -204,6 +208,7 @@ void | ||||
| SimpleDatabase::Close() | ||||
| { | ||||
| 	assert(root != NULL); | ||||
| 	assert(borrowed_song_count == 0); | ||||
|  | ||||
| 	directory_free(root); | ||||
| } | ||||
| @@ -219,10 +224,25 @@ SimpleDatabase::GetSong(const char *uri, GError **error_r) const | ||||
| 	if (song == NULL) | ||||
| 		g_set_error(error_r, db_quark(), DB_NOT_FOUND, | ||||
| 			    "No such song: %s", uri); | ||||
| #ifndef NDEBUG | ||||
| 	else | ||||
| 		++const_cast<unsigned &>(borrowed_song_count); | ||||
| #endif | ||||
|  | ||||
| 	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 | ||||
| const struct directory * | ||||
| SimpleDatabase::LookupDirectory(const char *uri) const | ||||
|   | ||||
| @@ -38,6 +38,10 @@ class SimpleDatabase : public Database { | ||||
|  | ||||
| 	time_t mtime; | ||||
|  | ||||
| #ifndef NDEBUG | ||||
| 	unsigned borrowed_song_count; | ||||
| #endif | ||||
|  | ||||
| public: | ||||
| 	gcc_pure | ||||
| 	struct directory *GetRoot() { | ||||
| @@ -61,6 +65,8 @@ public: | ||||
|  | ||||
| 	virtual struct song *GetSong(const char *uri_utf8, | ||||
| 				     GError **error_r) const override; | ||||
| 	virtual void ReturnSong(struct song *song) const; | ||||
|  | ||||
| 	virtual bool Visit(const DatabaseSelection &selection, | ||||
| 			   VisitDirectory visit_directory, | ||||
| 			   VisitSong visit_song, | ||||
|   | ||||
| @@ -128,7 +128,12 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc, | ||||
| 	if (song == NULL) | ||||
| 		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 | ||||
|   | ||||
| @@ -127,6 +127,7 @@ spl_print(struct client *client, const char *name_utf8, bool detail, | ||||
| 			struct song *song = db_get_song(temp); | ||||
| 			if (song) { | ||||
| 				song_print_info(client, song); | ||||
| 				db_return_song(song); | ||||
| 				wrote = true; | ||||
| 			} | ||||
| 		} | ||||
| @@ -157,8 +158,7 @@ playlist_provider_print(struct client *client, const char *uri, | ||||
| 		else | ||||
| 			song_print_uri(client, song); | ||||
|  | ||||
| 		if (!song_in_database(song) || song_is_detached(song)) | ||||
| 			song_free(song); | ||||
| 		song_free(song); | ||||
| 	} | ||||
|  | ||||
| 	g_free(base_uri); | ||||
|   | ||||
| @@ -41,8 +41,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, | ||||
| 	     ++i) { | ||||
| 		if (i < start_index) { | ||||
| 			/* skip songs before the start index */ | ||||
| 			if (!song_in_database(song)) | ||||
| 				song_free(song); | ||||
| 			song_free(song); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| @@ -51,9 +50,8 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, | ||||
| 			continue; | ||||
|  | ||||
| 		result = playlist_append_song(dest, pc, song, NULL); | ||||
| 		song_free(song); | ||||
| 		if (result != PLAYLIST_RESULT_SUCCESS) { | ||||
| 			if (!song_in_database(song)) | ||||
| 				song_free(song); | ||||
| 			g_free(base_uri); | ||||
| 			return result; | ||||
| 		} | ||||
|   | ||||
| @@ -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 */ | ||||
| 		tmp->tag->time = dest->tag->time - src->start_ms / 1000; | ||||
|  | ||||
| 	if (!song_in_database(dest)) | ||||
| 		song_free(dest); | ||||
|  | ||||
| 	song_free(dest); | ||||
| 	return tmp; | ||||
| } | ||||
|  | ||||
| @@ -97,10 +95,13 @@ playlist_check_load_song(const struct song *song, const char *uri, bool secure) | ||||
| 		if (dest == NULL) | ||||
| 			return NULL; | ||||
| 	} else { | ||||
| 		dest = db_get_song(uri); | ||||
| 		if (dest == NULL) | ||||
| 		struct song *tmp = db_get_song(uri); | ||||
| 		if (tmp == NULL) | ||||
| 			/* not found in database */ | ||||
| 			return NULL; | ||||
|  | ||||
| 		dest = song_dup_detached(tmp); | ||||
| 		db_return_song(tmp); | ||||
| 	} | ||||
|  | ||||
| 	return apply_song_metadata(dest, song); | ||||
|   | ||||
| @@ -103,4 +103,7 @@ queue_load_song(FILE *fp, GString *buffer, const char *line, | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
| 			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; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann