From 7823fae9d5d150451aa86fbde8d8f1799ee6accb Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Fri, 3 Dec 2004 06:43:20 +0000 Subject: [PATCH] Stop unchanged static playlists from incrementing version number. Fix memory leak with background rescans and static playlists --- src/db-gdbm.c | 152 ++++++++++++++++++++++++++++++++++++++++++++-- src/db-memory.h | 5 +- src/mp3-scanner.c | 9 ++- src/playlist.c | 2 +- 4 files changed, 158 insertions(+), 10 deletions(-) diff --git a/src/db-gdbm.c b/src/db-gdbm.c index 5cd78031..48c1d1ce 100644 --- a/src/db-gdbm.c +++ b/src/db-gdbm.c @@ -78,7 +78,9 @@ typedef struct tag_playlist { unsigned int id; int songs; int is_smart; + int found; char *name; + int file_time; struct tag_playlistentry *nodes; struct tag_playlist *next; } DB_PLAYLIST; @@ -157,6 +159,8 @@ static int db_unlock(void); static void db_gdbmlock(void); static int db_gdbmunlock(void); +static DB_PLAYLIST *db_playlist_find(int playlistid); + int db_start_initial_update(void); int db_end_initial_update(void); int db_is_empty(void); @@ -166,7 +170,8 @@ int db_deinit(void); int db_version(void); int db_add(MP3FILE *mp3file); int db_delete(int id); -int db_add_playlist(unsigned int playlistid, char *name, int is_smart); +int db_delete_playlist(unsigned int playlistid); +int db_add_playlist(unsigned int playlistid, char *name, int file_time, int is_smart); int db_add_playlist_song(unsigned int playlistid, unsigned int itemid); int db_unpackrecord(datum *pdatum, MP3FILE *pmp3); int db_scanning(void); @@ -413,6 +418,7 @@ int db_version(void) { int db_start_initial_update(void) { datum tmp_key,tmp_nextkey; int err; + DB_PLAYLIST *current; /* we need a write lock on the db -- stop enums from happening */ db_writelock(); @@ -448,6 +454,14 @@ int db_start_initial_update(void) { tmp_key=tmp_nextkey; } + + /* walk through the playlists and mark them as not found */ + current=db_playlists.next; + while(current) { + current->found=0; + current=current->next; + } + db_update_mode=1; db_unlock(); @@ -461,6 +475,8 @@ int db_start_initial_update(void) { */ int db_end_initial_update(void) { const void *val; + DB_PLAYLIST *current,*last; + DB_PLAYLISTENTRY *pple; DPRINTF(E_DBG,L_DB|L_SCAN,"Initial update over. Removing stale items\n"); for(val=rblookup(RB_LUFIRST,NULL,db_removed); val != NULL; @@ -479,6 +495,36 @@ int db_end_initial_update(void) { gdbm_reorganize(db_songs); gdbm_sync(db_songs); DPRINTF(E_DBG,L_DB,"Reorganize done\n"); + + + DPRINTF(E_DBG,L_DB|L_PL,"Finding deleted static playlists\n"); + + current=db_playlists.next; + last=&db_playlists; + + while(current) { + if((!current->found)&&(!current->is_smart)) { + DPRINTF(E_DBG,L_DB|L_PL,"Deleting playlist %s\n",current->name); + last->next=current->next; + if(current->nodes) + db_playlist_count--; + db_version_no++; + + while(current->nodes) { + pple=current->nodes; + current->nodes=pple->next; + free(pple); + } + + if(current->name) + free(current->name); + free(current); + + current=last; + } + current=current->next; + } + db_update_mode=0; db_gdbmunlock(); db_unlock(); @@ -498,15 +544,107 @@ int db_is_empty(void) { } +/** + * Get the pointer to a specific playlist. MUST HAVE A + * READLOCK TO CALL THIS! + * + * @param playlistid playlist to find + * @returns DB_PLAYLIST of playlist, or null otherwise. + */ +DB_PLAYLIST *db_playlist_find(int playlistid) { + DB_PLAYLIST *current; + + current=db_playlists.next; + while(current && (current->id != playlistid)) + current=current->next; + + if(!current) { + return NULL; + } + + return current; +} + +/** + * delete a given playlist + * + * @param playlistid playlist to delete + */ +int db_delete_playlist(unsigned int playlistid) { + DB_PLAYLIST *plist; + DB_PLAYLISTENTRY *pple; + DB_PLAYLIST *last, *current; + + DPRINTF(E_DBG,L_PL,"Deleting playlist %d\n",playlistid); + + db_writelock(); + + current=db_playlists.next; + last=&db_playlists; + + while(current && (current->id != playlistid)) { + last=current; + current=current->next; + } + + if(!current) { + db_unlock(); + return -1; + } + + last->next=current->next; + + if(current->nodes) + db_playlist_count--; + + db_version_no++; + + db_unlock(); + + while(current->nodes) { + pple=current->nodes; + current->nodes=pple->next; + free(pple); + } + + if(current->name) + free(current->name); + + free(current); + return 0; +} + +/** + * find the last modified time of a specific playlist + * + * @param playlistid playlist to check (inode) + * @returns file_time of playlist, or 0 if no playlist + */ +int db_playlist_last_modified(int playlistid) { + DB_PLAYLIST *plist; + int file_time; + + db_readlock(); + plist=db_playlist_find(playlistid); + if(!plist) { + db_unlock(); + return 0; + } + + file_time=plist->file_time; + + /* mark as found, so deleted playlists can go away */ + plist->found=1; + db_unlock(); + return file_time; +} + /* * db_add_playlist * * Add a new playlist - * - * FIXME: this assume we are in db_update mode... if this is called at random, - * then we have to get a write lock. */ -int db_add_playlist(unsigned int playlistid, char *name, int is_smart) { +int db_add_playlist(unsigned int playlistid, char *name, int file_time, int is_smart) { int err; DB_PLAYLIST *pnew; @@ -518,6 +656,8 @@ int db_add_playlist(unsigned int playlistid, char *name, int is_smart) { pnew->id=playlistid; pnew->nodes=NULL; pnew->songs=0; + pnew->found=1; + pnew->file_time=file_time; pnew->is_smart=is_smart; if(!pnew->name) { @@ -1259,7 +1399,7 @@ MP3FILE *db_find(int id) { /* FIXME: Not reentrant */ MEMNOTIFY(content.dptr); if(!content.dptr) { - DPRINTF(E_WARN,L_DB,"Could not find id %d\n",id); + DPRINTF(E_DBG,L_DB,"Could not find id %d\n",id); db_unlock(); return NULL; } diff --git a/src/db-memory.h b/src/db-memory.h index 8c37f184..ae2977ec 100644 --- a/src/db-memory.h +++ b/src/db-memory.h @@ -35,8 +35,9 @@ extern int db_deinit(void); extern int db_version(void); extern int db_add(MP3FILE *mp3file); extern int db_delete(int id); -extern int db_add_playlist(unsigned int playlistid, char *name, int is_smart); +extern int db_add_playlist(unsigned int playlistid, char *name, int file_time, int is_smart); extern int db_add_playlist_song(unsigned int playlistid, unsigned int itemid); +extern int db_delete_playlist(unsigned int playlistid); extern ENUMHANDLE db_enum_begin(void); extern MP3FILE *db_enum(ENUMHANDLE *handle); @@ -58,7 +59,7 @@ extern int db_playlist_items_enum(ENUMHANDLE *current); extern int db_playlist_items_enum_end(ENUMHANDLE handle); extern char *db_get_playlist_name(int playlistid); - +extern int db_playlist_last_modified(int playlistid); extern int db_scanning(void); /* For persistant databases only */ diff --git a/src/mp3-scanner.c b/src/mp3-scanner.c index cc040189..769b94cb 100644 --- a/src/mp3-scanner.c +++ b/src/mp3-scanner.c @@ -460,13 +460,20 @@ void scan_static_playlist(char *path, struct dirent *pde, struct stat *psb) { struct stat sb; DPRINTF(E_WARN,L_SCAN|L_PL,"Processing static playlist: %s\n",pde->d_name); + + /* see if we should update it */ + if(db_playlist_last_modified(psb->st_ino) == psb->st_mtime) + return; + + db_delete_playlist(psb->st_ino); + strcpy(m3u_path,pde->d_name); snprintf(playlist_path,sizeof(playlist_path),"%s/%s",path,pde->d_name); m3u_path[strlen(pde->d_name) - 4] = '\0'; playlistid=psb->st_ino; fd=open(playlist_path,O_RDONLY); if(fd != -1) { - db_add_playlist(playlistid,m3u_path,0); + db_add_playlist(playlistid,m3u_path,psb->st_mtime,0); DPRINTF(E_INF,L_SCAN|L_PL,"Added playlist as id %d\n",playlistid); memset(linebuffer,0x00,sizeof(linebuffer)); diff --git a/src/playlist.c b/src/playlist.c index 50e8bdb8..93068611 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -230,7 +230,7 @@ void pl_register(void) { pcurrent=pl_smart.next; while(pcurrent) { DPRINTF(E_INF,L_PL,"Adding smart playlist %s as %d\n",pcurrent->name,pcurrent->id) - db_add_playlist(pcurrent->id, pcurrent->name,1); + db_add_playlist(pcurrent->id, pcurrent->name,0,1); pcurrent=pcurrent->next; } }