update: replaced update_return with global "modified" flag
There is only once update thread at a time. Make the "modified" flag global and remove the return values of most functions. Propagating an error is only useful for updateDirectory(), since updateInDirectory() will delete failed subdirectories.
This commit is contained in:
106
src/update.c
106
src/update.c
@ -30,18 +30,14 @@
|
|||||||
#include "condition.h"
|
#include "condition.h"
|
||||||
#include "update.h"
|
#include "update.h"
|
||||||
|
|
||||||
enum update_return {
|
|
||||||
UPDATE_RETURN_ERROR = -1,
|
|
||||||
UPDATE_RETURN_NOUPDATE = 0,
|
|
||||||
UPDATE_RETURN_UPDATED = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum update_progress {
|
static enum update_progress {
|
||||||
UPDATE_PROGRESS_IDLE = 0,
|
UPDATE_PROGRESS_IDLE = 0,
|
||||||
UPDATE_PROGRESS_RUNNING = 1,
|
UPDATE_PROGRESS_RUNNING = 1,
|
||||||
UPDATE_PROGRESS_DONE = 2
|
UPDATE_PROGRESS_DONE = 2
|
||||||
} progress;
|
} progress;
|
||||||
|
|
||||||
|
static bool modified;
|
||||||
|
|
||||||
/* make this dynamic?, or maybe this is big enough... */
|
/* make this dynamic?, or maybe this is big enough... */
|
||||||
static char *update_paths[32];
|
static char *update_paths[32];
|
||||||
static size_t update_paths_nr;
|
static size_t update_paths_nr;
|
||||||
@ -130,7 +126,6 @@ delete_directory(struct directory *directory)
|
|||||||
struct delete_data {
|
struct delete_data {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
struct directory *dir;
|
struct directory *dir;
|
||||||
enum update_return ret;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* passed to songvec_for_each */
|
/* passed to songvec_for_each */
|
||||||
@ -144,32 +139,31 @@ delete_song_if_removed(struct song *song, void *_data)
|
|||||||
|
|
||||||
if (!isFile(data->tmp, NULL)) {
|
if (!isFile(data->tmp, NULL)) {
|
||||||
delete_song(data->dir, song);
|
delete_song(data->dir, song);
|
||||||
data->ret = UPDATE_RETURN_UPDATED;
|
modified = true;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum update_return
|
static void
|
||||||
delete_path(const char *path)
|
delete_path(const char *path)
|
||||||
{
|
{
|
||||||
struct directory *directory = db_get_directory(path);
|
struct directory *directory = db_get_directory(path);
|
||||||
struct song *song = db_get_song(path);
|
struct song *song = db_get_song(path);
|
||||||
|
|
||||||
if (directory != NULL)
|
if (directory != NULL) {
|
||||||
delete_directory(directory);
|
delete_directory(directory);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (song != NULL)
|
if (song != NULL) {
|
||||||
delete_song(song->parent, song);
|
delete_song(song->parent, song);
|
||||||
|
modified = true;
|
||||||
return directory == NULL && song == NULL
|
}
|
||||||
? UPDATE_RETURN_NOUPDATE
|
|
||||||
: UPDATE_RETURN_UPDATED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum update_return
|
static void
|
||||||
removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory)
|
removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory)
|
||||||
{
|
{
|
||||||
enum update_return ret = UPDATE_RETURN_NOUPDATE;
|
|
||||||
int i;
|
int i;
|
||||||
struct dirvec *dv = &directory->children;
|
struct dirvec *dv = &directory->children;
|
||||||
struct delete_data data;
|
struct delete_data data;
|
||||||
@ -179,15 +173,12 @@ removeDeletedFromDirectory(char *path_max_tmp, struct directory *directory)
|
|||||||
continue;
|
continue;
|
||||||
LOG("removing directory: %s\n", dv->base[i]->path);
|
LOG("removing directory: %s\n", dv->base[i]->path);
|
||||||
dirvec_delete(dv, dv->base[i]);
|
dirvec_delete(dv, dv->base[i]);
|
||||||
ret = UPDATE_RETURN_UPDATED;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.dir = directory;
|
data.dir = directory;
|
||||||
data.tmp = path_max_tmp;
|
data.tmp = path_max_tmp;
|
||||||
data.ret = ret;
|
|
||||||
songvec_for_each(&directory->songs, delete_song_if_removed, &data);
|
songvec_for_each(&directory->songs, delete_song_if_removed, &data);
|
||||||
|
|
||||||
return data.ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *opendir_path(char *path_max_tmp, const char *dirname)
|
static const char *opendir_path(char *path_max_tmp, const char *dirname)
|
||||||
@ -227,10 +218,10 @@ inodeFoundInParent(struct directory *parent, ino_t inode, dev_t device)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum update_return
|
static bool
|
||||||
updateDirectory(struct directory *directory, const struct stat *st);
|
updateDirectory(struct directory *directory, const struct stat *st);
|
||||||
|
|
||||||
static enum update_return
|
static void
|
||||||
updateInDirectory(struct directory *directory,
|
updateInDirectory(struct directory *directory,
|
||||||
const char *name, const struct stat *st)
|
const char *name, const struct stat *st)
|
||||||
{
|
{
|
||||||
@ -241,25 +232,23 @@ updateInDirectory(struct directory *directory,
|
|||||||
if (song == NULL) {
|
if (song == NULL) {
|
||||||
song = song_file_load(shortname, directory);
|
song = song_file_load(shortname, directory);
|
||||||
if (song == NULL)
|
if (song == NULL)
|
||||||
return -1;
|
return;
|
||||||
|
|
||||||
songvec_add(&directory->songs, song);
|
songvec_add(&directory->songs, song);
|
||||||
|
modified = true;
|
||||||
LOG("added %s\n", name);
|
LOG("added %s\n", name);
|
||||||
return UPDATE_RETURN_UPDATED;
|
|
||||||
} else if (st->st_mtime != song->mtime) {
|
} else if (st->st_mtime != song->mtime) {
|
||||||
LOG("updating %s\n", name);
|
LOG("updating %s\n", name);
|
||||||
if (!song_file_update(song))
|
if (!song_file_update(song))
|
||||||
delete_song(directory, song);
|
delete_song(directory, song);
|
||||||
return UPDATE_RETURN_UPDATED;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UPDATE_RETURN_NOUPDATE;
|
|
||||||
} else if (S_ISDIR(st->st_mode)) {
|
} else if (S_ISDIR(st->st_mode)) {
|
||||||
struct directory *subdir;
|
struct directory *subdir;
|
||||||
enum update_return ret;
|
bool ret;
|
||||||
|
|
||||||
if (inodeFoundInParent(directory, st->st_ino, st->st_dev))
|
if (inodeFoundInParent(directory, st->st_ino, st->st_dev))
|
||||||
return UPDATE_RETURN_ERROR;
|
return;
|
||||||
|
|
||||||
subdir = directory_get_child(directory, name);
|
subdir = directory_get_child(directory, name);
|
||||||
if (subdir == NULL)
|
if (subdir == NULL)
|
||||||
@ -268,13 +257,10 @@ updateInDirectory(struct directory *directory,
|
|||||||
assert(directory == subdir->parent);
|
assert(directory == subdir->parent);
|
||||||
|
|
||||||
ret = updateDirectory(subdir, st);
|
ret = updateDirectory(subdir, st);
|
||||||
if (ret == UPDATE_RETURN_ERROR || directory_is_empty(subdir))
|
if (!ret)
|
||||||
delete_directory(subdir);
|
delete_directory(subdir);
|
||||||
|
|
||||||
return ret;
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG("update: %s is not a directory or music\n", name);
|
DEBUG("update: %s is not a directory or music\n", name);
|
||||||
return UPDATE_RETURN_NOUPDATE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,14 +270,13 @@ static int skip_path(const char *path)
|
|||||||
return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0;
|
return (path[0] == '.' || strchr(path, '\n')) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum update_return
|
static bool
|
||||||
updateDirectory(struct directory *directory, const struct stat *st)
|
updateDirectory(struct directory *directory, const struct stat *st)
|
||||||
{
|
{
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
const char *dirname = directory_get_path(directory);
|
const char *dirname = directory_get_path(directory);
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
char path_max_tmp[MPD_PATH_MAX];
|
char path_max_tmp[MPD_PATH_MAX];
|
||||||
enum update_return ret = UPDATE_RETURN_NOUPDATE, ret2;
|
|
||||||
|
|
||||||
assert(S_ISDIR(st->st_mode));
|
assert(S_ISDIR(st->st_mode));
|
||||||
|
|
||||||
@ -299,10 +284,9 @@ updateDirectory(struct directory *directory, const struct stat *st)
|
|||||||
|
|
||||||
dir = opendir(opendir_path(path_max_tmp, dirname));
|
dir = opendir(opendir_path(path_max_tmp, dirname));
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return UPDATE_RETURN_ERROR;
|
return false;
|
||||||
|
|
||||||
if (removeDeletedFromDirectory(path_max_tmp, directory) > 0)
|
removeDeletedFromDirectory(path_max_tmp, directory);
|
||||||
ret = UPDATE_RETURN_UPDATED;
|
|
||||||
|
|
||||||
while ((ent = readdir(dir))) {
|
while ((ent = readdir(dir))) {
|
||||||
char *utf8;
|
char *utf8;
|
||||||
@ -320,17 +304,14 @@ updateDirectory(struct directory *directory, const struct stat *st)
|
|||||||
dirname, strlen(dirname));
|
dirname, strlen(dirname));
|
||||||
|
|
||||||
if (myStat(path_max_tmp, &st2) == 0)
|
if (myStat(path_max_tmp, &st2) == 0)
|
||||||
ret2 = updateInDirectory(directory, path_max_tmp,
|
updateInDirectory(directory, path_max_tmp, &st2);
|
||||||
&st2);
|
|
||||||
else
|
else
|
||||||
ret2 = delete_path(path_max_tmp);
|
delete_path(path_max_tmp);
|
||||||
if (ret == UPDATE_RETURN_NOUPDATE)
|
|
||||||
ret = ret2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
return ret;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct directory *
|
static struct directory *
|
||||||
@ -381,38 +362,35 @@ addParentPathToDB(const char *utf8path)
|
|||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum update_return updatePath(const char *path)
|
static void
|
||||||
|
updatePath(const char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (myStat(path, &st) < 0)
|
if (myStat(path, &st) == 0)
|
||||||
return delete_path(path);
|
updateInDirectory(addParentPathToDB(path), path, &st);
|
||||||
|
else
|
||||||
return updateInDirectory(addParentPathToDB(path), path, &st);
|
delete_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void * update_task(void *_path)
|
static void * update_task(void *_path)
|
||||||
{
|
{
|
||||||
enum update_return ret = UPDATE_RETURN_NOUPDATE;
|
|
||||||
|
|
||||||
if (_path != NULL && !isRootDirectory(_path)) {
|
if (_path != NULL && !isRootDirectory(_path)) {
|
||||||
ret = updatePath((char *)_path);
|
updatePath((char *)_path);
|
||||||
free(_path);
|
free(_path);
|
||||||
} else {
|
} else {
|
||||||
struct directory *directory = db_get_root();
|
struct directory *directory = db_get_root();
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (myStat(directory_get_path(directory), &st) == 0)
|
if (myStat(directory_get_path(directory), &st) == 0)
|
||||||
ret = updateDirectory(directory, &st);
|
updateDirectory(directory, &st);
|
||||||
else
|
|
||||||
ret = UPDATE_RETURN_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == UPDATE_RETURN_UPDATED && db_save() < 0)
|
if (modified)
|
||||||
ret = UPDATE_RETURN_ERROR;
|
db_save();
|
||||||
progress = UPDATE_PROGRESS_DONE;
|
progress = UPDATE_PROGRESS_DONE;
|
||||||
wakeup_main_task();
|
wakeup_main_task();
|
||||||
return (void *)ret;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spawn_update_task(char *path)
|
static void spawn_update_task(char *path)
|
||||||
@ -422,6 +400,7 @@ static void spawn_update_task(char *path)
|
|||||||
assert(pthread_equal(pthread_self(), main_task));
|
assert(pthread_equal(pthread_self(), main_task));
|
||||||
|
|
||||||
progress = UPDATE_PROGRESS_RUNNING;
|
progress = UPDATE_PROGRESS_RUNNING;
|
||||||
|
modified = false;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
if (pthread_create(&update_thr, &attr, update_task, path))
|
if (pthread_create(&update_thr, &attr, update_task, path))
|
||||||
FATAL("Failed to spawn update task: %s\n", strerror(errno));
|
FATAL("Failed to spawn update task: %s\n", strerror(errno));
|
||||||
@ -457,9 +436,6 @@ directory_update_init(char *path)
|
|||||||
|
|
||||||
void reap_update_task(void)
|
void reap_update_task(void)
|
||||||
{
|
{
|
||||||
void *thread_return;
|
|
||||||
enum update_return ret;
|
|
||||||
|
|
||||||
assert(pthread_equal(pthread_self(), main_task));
|
assert(pthread_equal(pthread_self(), main_task));
|
||||||
|
|
||||||
if (progress == UPDATE_PROGRESS_IDLE)
|
if (progress == UPDATE_PROGRESS_IDLE)
|
||||||
@ -477,10 +453,10 @@ void reap_update_task(void)
|
|||||||
|
|
||||||
if (progress != UPDATE_PROGRESS_DONE)
|
if (progress != UPDATE_PROGRESS_DONE)
|
||||||
return;
|
return;
|
||||||
if (pthread_join(update_thr, &thread_return))
|
if (pthread_join(update_thr, NULL))
|
||||||
FATAL("error joining update thread: %s\n", strerror(errno));
|
FATAL("error joining update thread: %s\n", strerror(errno));
|
||||||
ret = (enum update_return)(size_t)thread_return;
|
|
||||||
if (ret == UPDATE_RETURN_UPDATED)
|
if (modified)
|
||||||
playlistVersionChange();
|
playlistVersionChange();
|
||||||
|
|
||||||
if (update_paths_nr) {
|
if (update_paths_nr) {
|
||||||
|
Reference in New Issue
Block a user