Skip to content

Collections Design

Erik Massop edited this page Nov 4, 2017 · 1 revision

Now that the Collections Concept has been explained, we can define how collections will be implemented and use concretely, both in the server and as an API.

API Changes

Collection API

We first define new functions to work with collections.

// Creation/deletion xmmsc_coll_t* xmmsc_coll_new (xmmsc_coll_type_t type); void xmmsc_coll_free (xmmsc_coll_t* coll); // Setting properties void xmmsc_coll_set_idlist(xmmsc_coll_t* coll, unsigned int ids[]); void xmmsc_coll_add_operand(xmmsc_coll_t* coll, xmmsc_coll_t* op); void xmmsc_coll_remove_operand(xmmsc_coll_t* coll, xmmsc_coll_t* op); // Getting properties xmmsc_coll_type_t xmmsc_coll_get_type(xmmsc_coll_t* coll); unsigned int* xmmsc_coll_get_idlist(xmmsc_coll_t* coll); int xmmsc_coll_operand_list_first(xmmsc_coll_t* coll); int xmmsc_coll_operand_list_entry(xmmsc_coll_t* coll, xmmsc_coll_t** operands); int xmmsc_coll_operand_list_next(xmmsc_coll_t* coll); int xmmsc_coll_operand_list_save (xmmsc_coll_t *coll); int xmmsc_coll_operand_list_restore (xmmsc_coll_t *coll); // Attributes void xmmsc_coll_attribute_set(xmmsc_coll_t* coll, const char* key, const char* value); int  xmmsc_coll_attribute_remove(xmmsc_coll_t* coll, const char* key); int  xmmsc_coll_attribute_get(xmmsc_coll_t* coll, const char* key, char** value); void xmmsc_coll_attribute_foreach(xmmsc_coll_t* coll, xmmsc_coll_attribute_foreach_func func, void* user_data); // Idlist modifiers int xmmsc_coll_idlist_append (xmmsc_coll_t *coll, unsigned int id); int xmmsc_coll_idlist_insert (xmmsc_coll_t *coll, unsigned int id, unsigned int index); int xmmsc_coll_idlist_move (xmmsc_coll_t *coll, unsigned int index, unsigned int newindex); int xmmsc_coll_idlist_remove (xmmsc_coll_t *coll, unsigned int index); int xmmsc_coll_idlist_clear (xmmsc_coll_t *coll); int xmmsc_coll_idlist_get_index (xmmsc_coll_t *coll, unsigned int index, uint32_t *val); int xmmsc_coll_idlist_set_index (xmmsc_coll_t *coll, unsigned int index, uint32_t val); // Default "All Media" collection xmmsc_coll_t* xmmsc_coll_universe(); // Interact with server xmmsc_result_t* xmmsc_coll_get(xmmsc_connection_t*, char* collname, xmmsc_coll_namespace_t ns); // [xmmsc_coll_t] xmmsc_result_t* xmmsc_coll_list(xmmsc_connection_t*, xmmsc_coll_namespace_t ns);                // [list] xmmsc_result_t* xmmsc_coll_save(xmmsc_connection_t*, xmmsc_coll_t* coll,                                 char* name, xmmsc_coll_namespace_t ns);                         // [void] xmmsc_result_t* xmmsc_coll_rename (xmmsc_connection_t *, char* from_name, char* to_name,         // [void]                                   xmmsc_coll_namespace_t ns); xmmsc_result_t* xmmsc_coll_remove(xmmsc_connection_t*, char* name, xmmsc_coll_namespace_t ns);  // [void] int xmmsc_result_get_collection(xmmsc_result_t*, xmmsc_coll_t**); int xmmsc_result_get_dict_entry_collection(xmmsc_result_t*, xmmsc_coll_t**); // Search (in collections) xmmsc_result_t* xmmsc_coll_find(xmmsc_connection_t*, int mediaid, xmmsc_coll_namespace_t ns);  // [list<xmmsc_coll_t>] // Query xmmsc_result_t* xmmsc_coll_query_ids  (xmmsc_connection_t*, xmmsc_coll_t* coll,                                        const char **order, int limit_start, int limit_len); // [list] xmmsc_result_t* xmmsc_coll_query_infos(xmmsc_connection_t*, xmmsc_coll_t* coll,                                       const char **order, int limit_start, int limit_len,                                       const char **fetch, const char **group);            // [list] // Broadcast xmmsc_result_t *xmmsc_broadcast_collection_changed (xmmsc_connection_t *c);

Notes:

  • id lists are simply a 0-terminated array of unsigned integers.

Sample uses of the Collection API

Using idlists

Goal: initialize an idlist from the content collection "Foo".

xmmsc_result_t* res = xmmsc_coll_get (conn, "Foo", "Collections");  // get collection "Foo" xmmsc_result_wait (res) xmmsc_coll_t* some_coll; xmmsc_result_get_collection (res, &some_coll); unsigned int* ids = xmmsc_coll_get_idlist (some_coll); xmmsc_coll_t* idl_coll = xmmsc_coll_new (XMMS_COLL_TYPE_IDLIST); xmmsc_coll_set_idlist (idl_coll, ids); xmmsc_result_unref (res);

Using the AND operator and references

Goal: create a union of collection "Foo" and a custom collection (all media by Sonic Youth), and filter the resulting collection by year (only media from 2006).

xmmsc_coll_t* coll, operand; coll = xmmsc_coll_new (XMMS_COLL_TYPE_AND); // reference to collection Foo operand = xmmsc_coll_new (XMMS_COLL_TYPE_REFERENCE); xmmsc_coll_attribute_set(operand, "reference", "Foo"); xmmsc_coll_attribute_set(operand, "namespace", XMMS_COLLECTION_NS_COLLECTIONS); xmmsc_coll_add_operand (coll, operand); // custom collection (all media by Sonic Youth) operand = xmmsc_coll_new (XMMS_COLL_TYPE_MATCH); xmmsc_coll_t* allmedia = xmmsc_coll_universe (); xmmsc_coll_add_operand (operand, allmedia); xmmsc_coll_attribute_set(operand, "field", "artist"); xmmsc_coll_attribute_set(operand, "value", "Sonic Youth");   xmmsc_coll_add_operand (coll, operand); // Filter some more on year xmmsc_coll_t* last = xmmsc_coll_new (XMMS_COLL_TYPE_MATCH); xmmsc_coll_attribute_set(last, "field", "year"); xmmsc_coll_attribute_set(last, "value", "2006"); xmmsc_coll_add_operand (last, coll);

Querying a collection

Goal: Get the first 20 media of the collection "Svensk musik" when ordered by artist/album.

xmmsc_coll_t* qcoll = xmmsc_coll_new (XMMS_COLL_TYPE_REFERENCE); xmmsc_coll_attribute_set (qcoll, "name", "Svensk musik"); xmmsc_coll_attribute_set (qcoll, "namespace", XMMS_COLLECTION_NS_COLLECTIONS); xmmsc_result_t* res; char order[] = { "artist", "album", NULL }; res = xmmsc_coll_query_ids (conn, qcoll, order, 0, 20); xmmsc_result_wait (res); // ... browse results ... xmmsc_result_unref (res); xmmsc_coll_unref (qcoll);

Playlist API

Basically, all functions which altered the "active" playlist now take an extra playlist argument that specifies which playlist to modify. If set to NULL, the active playlist ("_active") is assumed. Note that ambiguous functions now have a _entry suffix (e.g. xmmsc_playlist_remove_entry, xmmsc_playlist_list_entries, etc). Sorting now takes a list of properties (not supported yet).

xmmsc_playlist_shuffle (xmmsc_connection_t *c, const char *playlist) xmmsc_playlist_sort (xmmsc_connection_t *c, const char *playlist, const char **properties) xmmsc_playlist_clear (xmmsc_connection_t *c, const char *playlist) xmmsc_playlist_insert_id (xmmsc_connection_t *c, const char *playlist, int pos, unsigned int id) xmmsc_playlist_insert_url (xmmsc_connection_t *c, const char *playlist, int pos, const char *url) xmmsc_playlist_list_entries (xmmsc_connection_t *c, const char *playlist) xmmsc_playlist_add_id (xmmsc_connection_t *c, const char *playlist, unsigned int id) xmmsc_playlist_add_url (xmmsc_connection_t *c, const char *playlist, const char *url) xmmsc_playlist_move_entry (xmmsc_connection_t *c, const char *playlist, unsigned int cur_pos, unsigned int new_pos) xmmsc_playlist_current_pos (xmmsc_connection_t *c, const char *playlist) xmmsc_playlist_remove_entry (xmmsc_connection_t *c, const char *playlist, unsigned int pos) xmmsc_broadcast_playlist_changed (xmmsc_connection_t *c) xmmsc_broadcast_playlist_current_pos (xmmsc_connection_t *c)

Additional functions moved from the Medialib module:

xmmsc_broadcast_playlist_loaded (xmmsc_connection_t *c) xmmsc_playlist_load (xmmsc_connection_t *conn, const char *playlist) xmmsc_playlist_list (xmmsc_connection_t *conn) xmmsc_playlist_remove (xmmsc_connection_t *conn, const char *playlist) xmmsc_playlist_export (xmmsc_connection_t *conn, const char *playlist, const char *mime) xmmsc_playlist_import (xmmsc_connection_t *conn, const char *playlist, const char *url)

Added functions:

xmmsc_playlist_add_collection (xmmsc_connection_t *c, const char *playlist, xmmsc_coll_t *coll, const char **order) xmmsc_playlist_insert_collection (xmmsc_connection_t *c, const char *playlist, int pos, xmmsc_coll_t *coll)

Medialib API

The Medialib API remains mostly unchanged, except for the removal of functions which are now irrelevant (including the raw SQL queries).

Removed functions:

xmmsc_medialib_select (xmmsc_connection_t *conn, const char *query) xmmsc_sqlite_prepare_string (const char *input) xmmsc_querygen_and (xmmsc_query_attribute_t *attributes, unsigned n) xmmsc_medialib_playlist_list (xmmsc_connection_t *conn, const char *playlist) xmmsc_medialib_playlist_save_current (xmmsc_connection_t *conn, const char *name)

Modified functions (moved to Playlist module):

xmmsc_medialib_add_to_playlist (xmmsc_connection_t *c, const char *query) xmmsc_medialib_playlist_load (xmmsc_connection_t *conn, const char *name) xmmsc_broadcast_medialib_playlist_loaded (xmmsc_connection_t *c) xmmsc_medialib_playlists_list (xmmsc_connection_t *conn) xmmsc_medialib_playlist_remove (xmmsc_connection_t *conn, const char *playlist) xmmsc_medialib_playlist_export (xmmsc_connection_t *conn, const char *playlist, const char *mime) xmmsc_medialib_playlist_import (xmmsc_connection_t *conn, const char *playlist, const char *url)

IPC Support

To be transfered by IPC, collection structures have to be serialized to a simple sequence of primitives already supported by IPC (integers and strings).

The following schema describes the serialized form of a collection:

+------------------------+ | uint type              | +------------------------+ | uint n_attributes      | +------------------------+ | string attrkey1        | | string attrval1        | | string attrkey2        | | string attrval2        | | ...                    | +------------------------+ | uint idlist_len        | +------------------------+ | uint idlist[0]         | | ...                    | < no terminal 0 +------------------------+ | uint n_operands        | +------------------------+ | +--------------------+ | < inlined operands (collections) | | int type   (OPER 1)| | | +--------------------+ | | | ...                | | < possibly more recursively | |                    | |   encapsulated operands | +--------------------+ | | +--------------------+ | | | int type   (OPER 2)| | | +--------------------+ | | | ...                | | | |                    | | | +--------------------+ | |  ...                   | +------------------------+

Server design

TBD:

  • flow, organization, commands
  • query generation
  • redesign playlists

Collection DAG serialization

To save the state of the collection DAG between server restarts, we serialize it in the database in several tables. The structure of the collection tables is presented below:

[CollectionLabels]            [CollectionOperators]         [CollectionAttributes] +-------------------+         +-------------------+         +-------------------+ |* collid       INT +----+--->o* id           INT o<---+----+* collid       INT | |  namespace    INT |    |    |  type         INT |    |    |* key      VARCHAR | |  name     VARCHAR |    |    +-------------------+    |    |  value    VARCHAR | +-------------------+    |                             |    +-------------------+                          |                             |                          |                             |                          |    [CollectionConnections]  |    [CollectionIdlists]                          |    +-------------------+    |    +-------------------+                          +----+* from_id      INT |    +----+* collid       INT |                               |* to_id        INT |         |* position     INT |                               +-------------------+         |  mid          INT |                                                             +-------------------+

Serialization to database is only performed on server shutdown. When it occurs, the tables are emptied and the structure saved from scratch.

Sample use of collections in XMMS2 cli

  • get (show struct)
  • list (list collections)
  • save (pattern/collection under the given name)
  • rename (a saved collection)
  • remove (a saved collection)
  • query (list collection content)
  • find (collections containing id X)

Implementation TODO

  • Collection struct
    • Definition
    • Functions to create, modify, delete collection structures
    • Support in IPC
    • Implementation testing
  • Server work
    • Deserialisation of collection objects
    • Collection querying
    • Playlists
    • Persistent storage
    • Testing of the different modules
Clone this wiki locally