aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2008-09-29 13:11:40 +0200
committerMax Kellermann <max@duempel.org>2008-09-29 13:11:40 +0200
commit3b8bc33a0454caf0521b4eb836ac0bbba293ece5 (patch)
tree901ae6f4ea8d0889216a75c4607289ccd4556c9c
parent029f607e159c17e4a66b30bf083d6c1ae02c669b (diff)
downloadmpd-3b8bc33a0454caf0521b4eb836ac0bbba293ece5.tar.gz
mpd-3b8bc33a0454caf0521b4eb836ac0bbba293ece5.tar.xz
mpd-3b8bc33a0454caf0521b4eb836ac0bbba293ece5.zip
directory: replace DirectoryList with dirvec
Small memory reduction compared to songvec since most users have much fewer dirs than songs, but still nice to have.
Diffstat (limited to '')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/directory.c291
-rw-r--r--src/directory.h7
-rw-r--r--src/dirvec.h73
4 files changed, 175 insertions, 197 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 5fc4be55f..d0ef815d2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -53,6 +53,7 @@ mpd_headers = \
decoder_api.h \
decoder_internal.h \
directory.h \
+ dirvec.h \
gcc.h \
decoder_list.h \
inputPlugins/_flac_common.h \
diff --git a/src/directory.c b/src/directory.c
index d051a9308..aa84d50b3 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -30,6 +30,7 @@
#include "song_print.h"
#include "song_save.h"
#include "main_notify.h"
+#include "dirvec.h"
#define DIRECTORY_DIR "directory: "
#define DIRECTORY_MTIME "mtime: "
@@ -60,14 +61,10 @@ static pthread_t update_thr;
static int directory_updateJobId;
-static DirectoryList *newDirectoryList(void);
-
static enum update_return
addToDirectory(Directory * directory,
const char *shortname, const char *name);
-static void freeDirectoryList(DirectoryList * list);
-
static void freeDirectory(Directory * directory);
static enum update_return exploreDirectory(Directory * directory);
@@ -188,11 +185,6 @@ static void directory_set_stat(Directory * dir, const struct stat *st)
dir->stat = 1;
}
-static DirectoryList *newDirectoryList(void)
-{
- return makeList((ListFreeDataFunc *) freeDirectory, 1);
-}
-
static Directory *newDirectory(const char *dirname, Directory * parent)
{
Directory *directory;
@@ -201,13 +193,6 @@ static Directory *newDirectory(const char *dirname, Directory * parent)
if (dirname && strlen(dirname))
directory->path = xstrdup(dirname);
- else
- directory->path = NULL;
- directory->subDirectories = newDirectoryList();
- assert(!directory->songs.base);
- directory->stat = 0;
- directory->inode = 0;
- directory->device = 0;
directory->parent = parent;
return directory;
@@ -215,7 +200,7 @@ static Directory *newDirectory(const char *dirname, Directory * parent)
static void freeDirectory(Directory * directory)
{
- freeDirectoryList(directory->subDirectories);
+ dirvec_destroy(&directory->children);
songvec_destroy(&directory->songs);
if (directory->path)
free(directory->path);
@@ -224,11 +209,6 @@ static void freeDirectory(Directory * directory)
/*getDirectoryPath(NULL); */
}
-static void freeDirectoryList(DirectoryList * directoryList)
-{
- freeList(directoryList);
-}
-
static void removeSongFromDirectory(Directory * directory, const char *shortname)
{
Song *song = songvec_find(&directory->songs, shortname);
@@ -243,27 +223,22 @@ static void removeSongFromDirectory(Directory * directory, const char *shortname
static void deleteEmptyDirectoriesInDirectory(Directory * directory)
{
- ListNode *node = directory->subDirectories->firstNode;
- ListNode *nextNode;
- Directory *subDir;
-
- while (node) {
- subDir = (Directory *) node->data;
- deleteEmptyDirectoriesInDirectory(subDir);
- nextNode = node->nextNode;
- if (subDir->subDirectories->numberOfNodes == 0 &&
- subDir->songs.nr == 0) {
- deleteNodeFromList(directory->subDirectories, node);
- }
- node = nextNode;
+ int i;
+ struct dirvec *dv = &directory->children;
+
+ for (i = dv->nr; --i >= 0; ) {
+ deleteEmptyDirectoriesInDirectory(dv->base[i]);
+ if (!dv->base[i]->children.nr && !dv->base[i]->songs.nr)
+ dirvec_delete(dv, dv->base[i]);
}
+ if (!dv->nr)
+ dirvec_destroy(dv);
}
static enum update_return updateInDirectory(Directory * directory,
const char *shortname, const char *name)
{
Song *song;
- void *subDir;
struct stat st;
if (myStat(name, &st))
@@ -280,10 +255,10 @@ static enum update_return updateInDirectory(Directory * directory,
return UPDATE_RETURN_UPDATED;
}
} else if (S_ISDIR(st.st_mode)) {
- if (findInList
- (directory->subDirectories, shortname, (void **)&subDir)) {
- directory_set_stat((Directory *)subDir, &st);
- return updateDirectory((Directory *) subDir);
+ Directory *subdir = dirvec_find(&directory->children, name);
+ if (subdir) {
+ directory_set_stat(subdir, &st);
+ return updateDirectory(subdir);
} else {
return addSubDirectoryToDirectory(directory, shortname,
name, &st);
@@ -304,29 +279,17 @@ removeDeletedFromDirectory(char *path_max_tmp, Directory * directory)
{
const char *dirname = (directory && directory->path) ?
directory->path : NULL;
- ListNode *node, *tmpNode;
- DirectoryList *subdirs = directory->subDirectories;
enum update_return ret = UPDATE_RETURN_NOUPDATE;
int i;
struct songvec *sv = &directory->songs;
+ struct dirvec *dv = &directory->children;
- node = subdirs->firstNode;
- while (node) {
- tmpNode = node->nextNode;
- if (node->key) {
- if (dirname)
- sprintf(path_max_tmp, "%s/%s", dirname,
- node->key);
- else
- strcpy(path_max_tmp, node->key);
-
- if (!isDir(path_max_tmp)) {
- LOG("removing directory: %s\n", path_max_tmp);
- deleteFromList(subdirs, node->key);
- ret = UPDATE_RETURN_UPDATED;
- }
- }
- node = tmpNode;
+ for (i = dv->nr; --i >= 0; ) {
+ if (isDir(dv->base[i]->path))
+ continue;
+ LOG("removing directory: %s\n", dv->base[i]->path);
+ dirvec_delete(dv, dv->base[i]);
+ ret = UPDATE_RETURN_UPDATED;
}
for (i = sv->nr; --i >= 0; ) { /* cleaner deletes if we go backwards */
@@ -354,7 +317,7 @@ static Directory *addDirectoryPathToDB(const char *utf8path,
char path_max_tmp[MPD_PATH_MAX];
char *parent;
Directory *parentDirectory;
- void *directory;
+ Directory *directory;
parent = parent_path(path_max_tmp, utf8path);
@@ -370,16 +333,14 @@ static Directory *addDirectoryPathToDB(const char *utf8path,
while (*(*shortname) && *(*shortname) == '/')
(*shortname)++;
- if (!findInList
- (parentDirectory->subDirectories, *shortname, &directory)) {
+ if (!(directory = dirvec_find(&parentDirectory->children, utf8path))) {
struct stat st;
if (myStat(utf8path, &st) < 0 ||
inodeFoundInParent(parentDirectory, st.st_ino, st.st_dev))
return NULL;
else {
directory = newDirectory(utf8path, parentDirectory);
- insertInList(parentDirectory->subDirectories,
- *shortname, directory);
+ dirvec_add(&parentDirectory->children, directory);
}
}
@@ -387,7 +348,7 @@ static Directory *addDirectoryPathToDB(const char *utf8path,
with potentially the same name */
removeSongFromDirectory(parentDirectory, *shortname);
- return (Directory *) directory;
+ return directory;
}
static Directory *addParentPathToDB(const char *utf8path, const char **shortname)
@@ -446,8 +407,7 @@ static enum update_return updatePath(const char *utf8path)
/* if updateDirectory fails, means we should delete it */
else {
LOG("removing directory: %s\n", path);
- deleteFromList(parentDirectory->subDirectories,
- shortname);
+ dirvec_delete(&parentDirectory->children, directory);
ret = UPDATE_RETURN_UPDATED;
/* don't return, path maybe a song now */
}
@@ -623,7 +583,7 @@ static int inodeFoundInParent(Directory * parent, ino_t inode, dev_t device)
}
static enum update_return addSubDirectoryToDirectory(Directory * directory,
- const char *shortname,
+ mpd_unused const char *shortname,
const char *name, struct stat *st)
{
Directory *subDirectory;
@@ -639,7 +599,7 @@ static enum update_return addSubDirectoryToDirectory(Directory * directory,
return UPDATE_RETURN_NOUPDATE;
}
- insertInList(directory->subDirectories, shortname, subDirectory);
+ dirvec_add(&directory->children, subDirectory);
return UPDATE_RETURN_UPDATED;
}
@@ -678,27 +638,6 @@ void closeMp3Directory(void)
freeDirectory(mp3rootDirectory);
}
-static Directory *findSubDirectory(Directory * directory, const char *name)
-{
- void *subDirectory;
- char *duplicated = xstrdup(name);
- char *key;
-
- key = strtok(duplicated, "/");
- if (!key) {
- free(duplicated);
- return NULL;
- }
-
- if (findInList(directory->subDirectories, key, &subDirectory)) {
- free(duplicated);
- return (Directory *) subDirectory;
- }
-
- free(duplicated);
- return NULL;
-}
-
int isRootDirectory(const char *name)
{
if (name == NULL || name[0] == '\0' || strcmp(name, "/") == 0) {
@@ -710,25 +649,34 @@ int isRootDirectory(const char *name)
static Directory *getSubDirectory(Directory * directory, const char *name,
const char **shortname)
{
- Directory *subDirectory;
- int len;
+ Directory *cur = directory;
+ Directory *found = NULL;
+ char *duplicated;
+ char *locate;
- if (isRootDirectory(name)) {
+ if (isRootDirectory(name))
return directory;
- }
- if ((subDirectory = findSubDirectory(directory, name)) == NULL)
- return NULL;
+ duplicated = xstrdup(name);
+ locate = strchr(duplicated, '/');
+ while (1) {
+ if (locate)
+ *locate = '\0';
+ if (!(found = dirvec_find(&cur->children, duplicated)))
+ break;
+ cur = found;
+ if (!locate)
+ break;
+ *locate = '/';
+ locate = strchr(locate + 1, '/');
+ }
- *shortname = name;
+ free(duplicated);
- len = 0;
- while (name[len] != '/' && name[len] != '\0')
- len++;
- while (name[len] == '/')
- len++;
+ if (found && (!(*shortname = strrchr(found->path, '/'))))
+ *shortname = found->path;
- return getSubDirectory(subDirectory, &(name[len]), shortname);
+ return found;
}
static Directory *getDirectoryDetails(const char *name, const char **shortname)
@@ -745,16 +693,13 @@ static Directory *getDirectory(const char *name)
return getSubDirectory(mp3rootDirectory, name, &shortname);
}
-static int printDirectoryList(struct client *client, DirectoryList * directoryList)
+static int printDirectoryList(struct client *client, struct dirvec *dv)
{
- ListNode *node = directoryList->firstNode;
- Directory *directory;
+ size_t i;
- while (node != NULL) {
- directory = (Directory *) node->data;
- client_printf(client, "%s%s\n", DIRECTORY_DIR,
- getDirectoryPath(directory));
- node = node->nextNode;
+ for (i = 0; i < dv->nr; ++i) {
+ client_printf(client, DIRECTORY_DIR "%s\n",
+ getDirectoryPath(dv->base[i]));
}
return 0;
@@ -767,16 +712,17 @@ int printDirectoryInfo(struct client *client, const char *name)
if ((directory = getDirectory(name)) == NULL)
return -1;
- printDirectoryList(client, directory->subDirectories);
+ printDirectoryList(client, &directory->children);
songvec_print(client, &directory->songs);
return 0;
}
+/* TODO error checking */
static void writeDirectoryInfo(FILE * fp, Directory * directory)
{
- ListNode *node = (directory->subDirectories)->firstNode;
- Directory *subDirectory;
+ struct dirvec *children = &directory->children;
+ size_t i;
int retv;
if (directory->path) {
@@ -788,15 +734,20 @@ static void writeDirectoryInfo(FILE * fp, Directory * directory)
}
}
- while (node != NULL) {
- subDirectory = (Directory *) node->data;
- retv = fprintf(fp, "%s%s\n", DIRECTORY_DIR, node->key);
+ for (i = 0; i < children->nr; ++i) {
+ Directory *cur = children->base[i];
+ const char *base = strrchr(cur->path, '/');
+
+ base = base ? base + 1 : cur->path;
+ assert(*base);
+
+ retv = fprintf(fp, DIRECTORY_DIR "%s\n", base);
if (retv < 0) {
- ERROR("Failed to write data to database file: %s\n",strerror(errno));
+ ERROR("Failed to write data to database file: %s\n",
+ strerror(errno));
return;
}
- writeDirectoryInfo(fp, subDirectory);
- node = node->nextNode;
+ writeDirectoryInfo(fp, cur);
}
songvec_save(fp, &directory->songs);
@@ -817,10 +768,7 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
int bufferSize = MPD_PATH_MAX * 2;
char key[MPD_PATH_MAX * 2];
Directory *subDirectory;
- int strcmpRet;
char *name;
- ListNode *nextDirNode = directory->subDirectories->firstNode;
- ListNode *nodeTemp;
while (myFgets(buffer, bufferSize, fp)
&& prefixcmp(buffer, DIRECTORY_END)) {
@@ -836,31 +784,8 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
if (prefixcmp(buffer, DIRECTORY_BEGIN))
FATAL("Error reading db at line: %s\n", buffer);
name = &(buffer[strlen(DIRECTORY_BEGIN)]);
-
- while (nextDirNode && (strcmpRet =
- strcmp(key,
- nextDirNode->key)) > 0) {
- nodeTemp = nextDirNode->nextNode;
- deleteNodeFromList(directory->subDirectories,
- nextDirNode);
- nextDirNode = nodeTemp;
- }
-
- if (NULL == nextDirNode) {
- subDirectory = newDirectory(name, directory);
- insertInList(directory->subDirectories,
- key, (void *)subDirectory);
- } else if (strcmpRet == 0) {
- subDirectory = (Directory *) nextDirNode->data;
- nextDirNode = nextDirNode->nextNode;
- } else {
- subDirectory = newDirectory(name, directory);
- insertInListBeforeNode(directory->
- subDirectories,
- nextDirNode, -1, key,
- (void *)subDirectory);
- }
-
+ subDirectory = newDirectory(name, directory);
+ dirvec_add(&directory->children, subDirectory);
readDirectoryInfo(fp, subDirectory);
} else if (!prefixcmp(buffer, SONG_BEGIN)) {
readSongInfoIntoList(fp, &directory->songs, directory);
@@ -868,27 +793,18 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
FATAL("Unknown line in db: %s\n", buffer);
}
}
-
- while (nextDirNode) {
- nodeTemp = nextDirNode->nextNode;
- deleteNodeFromList(directory->subDirectories, nextDirNode);
- nextDirNode = nodeTemp;
- }
}
static void sortDirectory(Directory * directory)
{
- ListNode *node = directory->subDirectories->firstNode;
- Directory *subDir;
+ int i;
+ struct dirvec *dv = &directory->children;
- sortList(directory->subDirectories);
+ dirvec_sort(dv);
songvec_sort(&directory->songs);
- while (node != NULL) {
- subDir = (Directory *) node->data;
- sortDirectory(subDir);
- node = node->nextNode;
- }
+ for (i = dv->nr; --i >= 0; )
+ sortDirectory(dv->base[i]);
}
int checkDirectoryDB(void)
@@ -1074,9 +990,9 @@ static int traverseAllInSubDirectory(Directory * directory,
int (*forEachDir) (Directory *, void *),
void *data)
{
- ListNode *node;
- Directory *dir;
+ struct dirvec *dv = &directory->children;
int errFlag = 0;
+ size_t j;
if (forEachDir) {
errFlag = forEachDir(directory, data);
@@ -1096,14 +1012,9 @@ static int traverseAllInSubDirectory(Directory * directory,
}
}
- node = directory->subDirectories->firstNode;
-
- while (node != NULL && !errFlag) {
- dir = (Directory *) node->data;
- errFlag = traverseAllInSubDirectory(dir, forEachSong,
+ for (j = 0; !errFlag && j < dv->nr; ++j)
+ errFlag = traverseAllInSubDirectory(dv->base[j], forEachSong,
forEachDir, data);
- node = node->nextNode;
- }
return errFlag;
}
@@ -1137,43 +1048,33 @@ void initMp3Directory(void)
static Song *getSongDetails(const char *file, const char **shortnameRet,
Directory ** directoryRet)
{
- Song *song;
+ Song *song = NULL;
Directory *directory;
char *dir = NULL;
char *duplicated = xstrdup(file);
- char *shortname = duplicated;
- char *c = strtok(duplicated, "/");
+ char *shortname = strrchr(duplicated, '/');
DEBUG("get song: %s\n", file);
- while (c) {
- shortname = c;
- c = strtok(NULL, "/");
- }
-
- if (shortname != duplicated) {
- for (c = duplicated; c < shortname - 1; c++) {
- if (*c == '\0')
- *c = '/';
- }
+ if (!shortname) {
+ shortname = duplicated;
+ } else {
+ *shortname = '\0';
+ ++shortname;
dir = duplicated;
}
- if (!(directory = getDirectory(dir))) {
- free(duplicated);
- return NULL;
- }
-
- if (!(song = songvec_find(&directory->songs, shortname))) {
- free(duplicated);
- return NULL;
- }
+ if (!(directory = getDirectory(dir)))
+ goto out;
+ if (!(song = songvec_find(&directory->songs, shortname)))
+ goto out;
- free(duplicated);
if (shortnameRet)
- *shortnameRet = shortname;
+ *shortnameRet = song->url;
if (directoryRet)
*directoryRet = directory;
+out:
+ free(duplicated);
return song;
}
diff --git a/src/directory.h b/src/directory.h
index 320a93a7f..e7917c8cd 100644
--- a/src/directory.h
+++ b/src/directory.h
@@ -23,11 +23,14 @@
#include "songvec.h"
#include "list.h"
-typedef List DirectoryList;
+struct dirvec {
+ struct _Directory **base;
+ size_t nr;
+};
typedef struct _Directory {
char *path;
- DirectoryList *subDirectories;
+ struct dirvec children;
struct songvec songs;
struct _Directory *parent;
ino_t inode;
diff --git a/src/dirvec.h b/src/dirvec.h
new file mode 100644
index 000000000..8b2f634e2
--- /dev/null
+++ b/src/dirvec.h
@@ -0,0 +1,73 @@
+#ifndef DIRVEC_H
+#define DIRVEC_H
+
+#include "directory.h"
+#include "os_compat.h"
+#include "utils.h"
+
+static size_t dv_size(struct dirvec *dv)
+{
+ return dv->nr * sizeof(Directory *);
+}
+
+/* Only used for sorting/searching a dirvec, not general purpose compares */
+static int dirvec_cmp(const void *d1, const void *d2)
+{
+ const Directory *a = ((const Directory * const *)d1)[0];
+ const Directory *b = ((const Directory * const *)d2)[0];
+ return strcmp(a->path, b->path);
+}
+
+static void dirvec_sort(struct dirvec *dv)
+{
+ qsort(dv->base, dv->nr, sizeof(Directory *), dirvec_cmp);
+}
+
+static Directory *dirvec_find(struct dirvec *dv, const char *path)
+{
+ int i;
+
+ for (i = dv->nr; --i >= 0; )
+ if (!strcmp(dv->base[i]->path, path))
+ return dv->base[i];
+ return NULL;
+}
+
+static int dirvec_delete(struct dirvec *dv, Directory *del)
+{
+ int i;
+
+ for (i = dv->nr; --i >= 0; ) {
+ if (dv->base[i] != del)
+ continue;
+ /* we _don't_ call freeDirectory() here */
+ if (!--dv->nr) {
+ free(dv->base);
+ dv->base = NULL;
+ } else {
+ memmove(&dv->base[i], &dv->base[i + 1],
+ (dv->nr - i + 1) * sizeof(Directory *));
+ dv->base = xrealloc(dv->base, dv_size(dv));
+ }
+ return i;
+ }
+
+ return -1; /* not found */
+}
+
+static void dirvec_add(struct dirvec *dv, Directory *add)
+{
+ ++dv->nr;
+ dv->base = xrealloc(dv->base, dv_size(dv));
+ dv->base[dv->nr - 1] = add;
+}
+
+static void dirvec_destroy(struct dirvec *dv)
+{
+ if (dv->base) {
+ free(dv->base);
+ dv->base = NULL;
+ }
+ dv->nr = 0;
+}
+#endif /* DIRVEC_H */