diff --git a/inc/lektor/common.h b/inc/lektor/common.h index 628a3d8562369897832f0ee920e3f500be2324ab..f2248888a7dcb368c7cc6b84f6e88a74ad923128 100644 --- a/inc/lektor/common.h +++ b/inc/lektor/common.h @@ -62,6 +62,13 @@ extern EXIT_FUNCTION ___not_implemented(const char *func, char *file, int line); GOTO_IF(pthread_mutex_unlock(&(lock)), "Failed to unlock", error); \ } +#define DO_WITH_RELAXED_LOCK(lock, error, instruction) \ + { \ + GOTO_IF(pthread_mutex_unlock(&(lock)), "Failed to unlock", error); \ + instruction; \ + GOTO_IF(pthread_mutex_lock(&(lock)), "Failed to lock", error); \ + } + #define STRTOL_ERROR(integer) (errno == ERANGE || (errno != 0 && (integer) == 0)) #define STRTOL(ret, str, endptr, err_flag) \ { \ diff --git a/src/module/module_repo.c b/src/module/module_repo.c index 052357a0b75cdaa6e2cb3bf4f23243a719a29dad..e3618640babd9c5e01ae7deed6bef1b7a3438ff7 100644 --- a/src/module/module_repo.c +++ b/src/module/module_repo.c @@ -95,6 +95,14 @@ struct ___file { int fd; }; +/***************************** + * Some forward declarations * + *****************************/ + +PRIVATE_FUNCTION void *___worker_update(void UNUSED *worker, void *___repo); +PRIVATE_FUNCTION void *___worker_dry_update(void UNUSED *worker, void *___repo); +PRIVATE_FUNCTION void *___worker_import_favorites(void *worker, void *___repo); + /********************* * Private functions * *********************/ @@ -586,7 +594,7 @@ ___worker_update(void UNUSED *worker, void *___args) lkt_queue_send(repo->queue, LKT_EVENT_DB_UPDATING, LKT_DB_UPDATING_PROGRESS); - DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating &= REPO_UPDATE_KARA); + DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating |= REPO_UPDATE_KARA); LOG_INFO("REPO", "Download kara list from %s", repo->name); if (___json_dl(repo->get_all_json, &json)) { @@ -623,13 +631,13 @@ end_no_lock: // Failed to take a lock } PRIVATE_FUNCTION void * -___worker_dry_update(void UNUSED *worker, void *___repo) +___worker_dry_update(void *worker, void *___repo) { struct module_repo_internal *repo = ___repo; struct lkt_uri *null_uri = lkt_uri_new(); lkt_queue_send(repo->queue, LKT_EVENT_DB_UPDATING, LKT_DB_UPDATING_PROGRESS); - DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating &= REPO_UPDATE_KARA); + DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating |= REPO_UPDATE_KARA); char *json = NULL; LOG_INFO("REPO", "Download kara list from %s (%s)", repo->name, repo->get_all_json); @@ -644,7 +652,17 @@ ___worker_dry_update(void UNUSED *worker, void *___repo) LOG_INFO("REPO", "Finished to download kara list"); LOG_INFO("REPO", "Don't delete kara on dry-update"); - database_updated(repo->db); + DO_WITH_LOCK(repo->mtx, after_import, { + if (repo->updating & REPO_UPDATE_FAV) { + LOG_INFO("REPO", "Skip the favorite update because one is already running"); + } else { + repo->updating |= REPO_UPDATE_FAV; + LOG_INFO("REPO", "End the dry-update by an import"); + DO_WITH_RELAXED_LOCK(repo->mtx, end_no_lock, + { ___worker_import_favorites(worker, repo); }); + } + }); +after_import: DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating &= (~REPO_UPDATE_KARA)); @@ -666,7 +684,7 @@ ___worker_rescan(void UNUSED *worker, void *___repo) return NULL; } - DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating &= REPO_UPDATE_KARA); + DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating |= REPO_UPDATE_KARA); #pragma message(TODO "Pass the check stop condition to the database_update from the REPO module") #pragma message(TODO "Here we never check timestamp, but sometimes we might want it...") @@ -793,7 +811,7 @@ ___worker_import_favorites(void *worker, void *___repo) .real_arg = (void *)repo, }; - DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating &= REPO_UPDATE_FAV); + DO_WITH_LOCK(repo->mtx, end_no_lock, repo->updating |= REPO_UPDATE_FAV); char *json; LOG_INFO("REPO", "Download fav lists: %s", repo->get_fav_json); @@ -972,7 +990,7 @@ mod_update(va_list *va) LOG_WARN("REPO", "Already updating"); else { - (*repo)->updating &= REPO_UPDATE_KARA; + (*repo)->updating |= REPO_UPDATE_KARA; struct update_worker_argument *args = LKT_ALLOC_STRUCT(update_worker_argument); args->repo = *repo; @@ -1007,7 +1025,7 @@ mod_dry_update(va_list *va) LOG_WARN("REPO", "Already updating"); else { - (*repo)->updating &= REPO_UPDATE_KARA; + (*repo)->updating |= REPO_UPDATE_KARA; if (worker_pool_push(&(*repo)->workers, ___worker_dry_update, (void *)*repo)) { LOG_ERROR("REPO", "Out of memory"); ret = 1; @@ -1035,7 +1053,7 @@ mod_rescan(va_list *va) LOG_WARN("REPO", "Already updating"); else { - (*repo)->updating &= REPO_UPDATE_KARA; + (*repo)->updating |= REPO_UPDATE_KARA; if (worker_pool_push(&(*repo)->workers, ___worker_rescan, (void *)*repo)) { LOG_ERROR("REPO", "Out of memory"); ret = 1; @@ -1058,21 +1076,20 @@ mod_import(va_list *va) repo = (struct module_repo_internal **)va_arg(copy, void **); int ret = 0; - GOTO_IF(pthread_mutex_lock(&(*repo)->mtx), "Failed to lock", end_no_lock); - if ((*repo)->updating & REPO_UPDATE_FAV) { - LOG_WARN("REPO", "Already importing favorites"); - goto end; - } - (*repo)->updating &= REPO_UPDATE_FAV; + DO_WITH_LOCK((*repo)->mtx, end_no_lock, { + if ((*repo)->updating & REPO_UPDATE_FAV) + LOG_WARN("REPO", "Already importing favorites"); - if (worker_pool_push(&(*repo)->workers, ___worker_import_favorites, (void *)*repo)) { - LOG_ERROR("REPO", "Out of memory"); - ret = 1; - goto end; - } + else { + (*repo)->updating |= REPO_UPDATE_FAV; + + if (worker_pool_push(&(*repo)->workers, ___worker_import_favorites, (void *)*repo)) { + LOG_ERROR("REPO", "Out of memory"); + ret = 1; + } + } + }); -end: - GOTO_IF(pthread_mutex_unlock(&(*repo)->mtx), "Failed to unlock", end_no_lock); end_no_lock: va_end(copy); return ret;