+/** @brief Retrieve the most recently added tracks
+ * @param ntracksp Where to put count, or 0
+ * @param maxtracks Maximum number of tracks to retrieve
+ * @return null-terminated array of track names
+ *
+ * The most recently added track is first in the array.
+ */
+char **trackdb_new(int *ntracksp,
+ int maxtracks) {
+ DB_TXN *tid;
+ char **tracks;
+
+ for(;;) {
+ tid = trackdb_begin_transaction();
+ tracks = trackdb_new_tid(ntracksp, maxtracks, tid);
+ if(tracks)
+ break;
+ trackdb_abort_transaction(tid);
+ }
+ trackdb_commit_transaction(tid);
+ return tracks;
+}
+
+/** @brief Retrieve the most recently added tracks
+ * @param ntracksp Where to put count, or 0
+ * @param maxtracks Maximum number of tracks to retrieve, or 0 for all
+ * @param tid Transaction ID
+ * @return null-terminated array of track names, or NULL on deadlock
+ *
+ * The most recently added track is first in the array.
+ */
+static char **trackdb_new_tid(int *ntracksp,
+ int maxtracks,
+ DB_TXN *tid) {
+ DBC *c;
+ DBT k, d;
+ int err = 0;
+ struct vector tracks[1];
+
+ vector_init(tracks);
+ c = trackdb_opencursor(trackdb_noticeddb, tid);
+ while((maxtracks <= 0 || tracks->nvec < maxtracks)
+ && !(err = c->c_get(c, prepare_data(&k), prepare_data(&d), DB_PREV)))
+ vector_append(tracks, xstrndup(d.data, d.size));
+ switch(err) {
+ case 0: /* hit maxtracks */
+ case DB_NOTFOUND: /* ran out of tracks */
+ break;
+ case DB_LOCK_DEADLOCK:
+ trackdb_closecursor(c);
+ return 0;
+ default:
+ fatal(0, "error reading noticed.db: %s", db_strerror(err));
+ }
+ if((err = trackdb_closecursor(c)))
+ return 0; /* deadlock */
+ vector_terminate(tracks);
+ if(ntracksp)
+ *ntracksp = tracks->nvec;
+ return tracks->vec;
+}
+