From 1ed640da24eb97255328c4498035ba524f6265fc Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Wed, 4 Oct 2023 08:51:10 -0400 Subject: [Feature] db_commit plugin allows a more verbose commit prints logf messages to the screen buffer and dumps the output to .rockbox/db_commit_log.txt logs warnings about tags that can't be displayed by the current font adds an option to the tagcache using the file .rockbox/database_commit.ignore to prevent auto commit Change-Id: Ib381b3b6d9dd19d76c95d0e87e605f7378e29674 --- apps/plugin.c | 2 +- apps/plugin.h | 2 +- apps/plugins/CATEGORIES | 1 + apps/plugins/SOURCES | 1 + apps/plugins/SUBDIRS | 1 + apps/plugins/SUBDIRS.app_build | 1 + apps/plugins/tagcache/SOURCES | 2 + apps/plugins/tagcache/tagcache.c | 581 ++++++++++++++++++++++++++++++++++ apps/plugins/tagcache/tagcache.h | 25 ++ apps/plugins/tagcache/tagcache.make | 30 ++ apps/tagcache.c | 70 +++- apps/tagcache.h | 1 + manual/rockbox_interface/tagcache.tex | 9 + 13 files changed, 707 insertions(+), 19 deletions(-) create mode 100644 apps/plugins/tagcache/SOURCES create mode 100644 apps/plugins/tagcache/tagcache.c create mode 100644 apps/plugins/tagcache/tagcache.h create mode 100644 apps/plugins/tagcache/tagcache.make diff --git a/apps/plugin.c b/apps/plugin.c index b1188fc183..e916918f23 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -832,7 +832,7 @@ static const struct plugin_api rockbox_api = { /* new stuff at the end, sort into place next time the API gets incompatible */ - + tagcache_commit_finalize, }; static int plugin_buffer_handle; diff --git a/apps/plugin.h b/apps/plugin.h index 11adf61e9c..4f9027987f 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -969,7 +969,7 @@ struct plugin_api { #endif /* new stuff at the end, sort into place next time the API gets incompatible */ - + void (*tagcache_commit_finalize)(void); }; /* plugin header */ diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 9ec38ab76b..49016fef13 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -22,6 +22,7 @@ clock,apps codebuster,games credits,viewers cube,demos +db_commit,apps db_folder_select,viewers demystify,demos dice,games diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 7edc8a3c51..b857f26ba5 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -4,6 +4,7 @@ battery_bench.c #endif #ifdef HAVE_TAGCACHE db_folder_select.c +tagcache/tagcache.c #endif chessclock.c credits.c diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index 4cb57edb1b..b9c18b5fd9 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS @@ -31,6 +31,7 @@ rockboy #if defined(HAVE_TAGCACHE) pictureflow +tagcache #endif #if PLUGIN_BUFFER_SIZE > 0x20000 diff --git a/apps/plugins/SUBDIRS.app_build b/apps/plugins/SUBDIRS.app_build index 1fc283d6c4..fbf83f01da 100644 --- a/apps/plugins/SUBDIRS.app_build +++ b/apps/plugins/SUBDIRS.app_build @@ -17,6 +17,7 @@ reversi #ifdef HAVE_TAGCACHE pictureflow +tagcache #endif /* For all the swcodec targets */ diff --git a/apps/plugins/tagcache/SOURCES b/apps/plugins/tagcache/SOURCES new file mode 100644 index 0000000000..2541f3e87c --- /dev/null +++ b/apps/plugins/tagcache/SOURCES @@ -0,0 +1,2 @@ +tagcache.c + diff --git a/apps/plugins/tagcache/tagcache.c b/apps/plugins/tagcache/tagcache.c new file mode 100644 index 0000000000..25ba9bc301 --- /dev/null +++ b/apps/plugins/tagcache/tagcache.c @@ -0,0 +1,581 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2023 by William Wilgus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/*Plugin Includes*/ + +#include "plugin.h" +/* Redefinitons of ANSI C functions. */ +#include "lib/wrappers.h" +#include "lib/helper.h" + +static void thread_create(void); +static void thread(void); /* the thread running it all */ +static void allocate_tempbuf(void); +static void free_tempbuf(void); +static bool do_timed_yield(void); +static void _log(const char *fmt, ...); +/*Aliases*/ +#if 0 +#ifdef ROCKBOX_HAS_LOGF + #define logf rb->logf +#else + #define logf(...) {} +#endif +#endif + + +#define logf _log +#define sleep rb->sleep +#define qsort rb->qsort + +#define write(x,y,z) rb->write(x,y,z) +#define ftruncate rb->ftruncate +#define remove rb->remove + +#define vsnprintf rb->vsnprintf +#define mkdir rb->mkdir +#define filesize rb->filesize + +#define strtok_r rb->strtok_r +#define strncasecmp rb->strncasecmp +#define strcasecmp rb->strcasecmp + +#define current_tick (*rb->current_tick) +#define crc_32(x,y,z) rb->crc_32(x,y,z) + + +#ifndef SIMULATOR +#define errno (*rb->__errno()) +#endif +#define ENOENT 2 /* No such file or directory */ +#define EEXIST 17 /* File exists */ +#define MAX_LOG_SIZE 16384 + +#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0xFF) +#define EV_ACTION MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x02) +#define EV_STARTUP MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0x01) + +/* communication to the worker thread */ +static struct +{ + int user_index; + bool exiting; /* signal to the thread that we want to exit */ + bool resume; + unsigned int id; /* worker thread id */ + struct event_queue queue; /* thread event queue */ + long last_useraction_tick; +} gThread; + + +/*Support Fns*/ +/* open but with a builtin printf for assembling the path */ +int open_pathfmt(char *buf, size_t size, int oflag, const char *pathfmt, ...) +{ + va_list ap; + va_start(ap, pathfmt); + vsnprintf(buf, size, pathfmt, ap); + va_end(ap); + if ((oflag & O_PATH) == O_PATH) + return -1; + int handle = open(buf, oflag, 0666); + //logf("Open: %s %d flag: %x", buf, handle, oflag); + return handle; +} + +static void sleep_yield(void) +{ + rb->queue_remove_from_head(&gThread.queue, EV_ACTION); + rb->queue_post(&gThread.queue, EV_ACTION, 0); + sleep(1); + #undef yield + rb->yield(); + #define yield sleep_yield +} + +/* make sure tag can be displayed by font pf*/ +static bool text_is_displayable(struct font *pf, unsigned char *src) +{ + unsigned short code; + const unsigned char *ptr = src; + while(*ptr) + { + ptr = rb->utf8decode(ptr, &code); + + if(!rb->font_get_bits(pf, code)) + { + return false; + } + } + return true; +} + +/* callback for each tag if false returned tag will not be added */ +bool user_check_tag(int index_type, char* build_idx_buf) +{ + static struct font *pf = NULL; + if (!pf) + pf = rb->font_get(FONT_UI); + + if (index_type == tag_artist || index_type == tag_album || + index_type == tag_genre || index_type == tag_title || + index_type == tag_composer || index_type == tag_comment || + index_type == tag_albumartist || index_type == tag_virt_canonicalartist) + { + /* this could be expanded with more rules / transformations */ + if (rb->utf8length(build_idx_buf) != strlen(build_idx_buf)) + { + if (!text_is_displayable(pf, build_idx_buf)) + { + logf("Can't display (%d) %s", index_type, build_idx_buf); + } + } + } + return true; +} + +/* undef features we don't need */ +#undef HAVE_DIRCACHE +#undef HAVE_TC_RAMCACHE +#undef HAVE_EEPROM_SETTINGS +/* paste the whole tagcache.c file */ +#include "../tagcache.c" + +static bool logdump(bool append); +static unsigned char logbuffer[MAX_LOG_SIZE + 1]; +static int logindex; +static bool logwrap; +static bool logenabled = true; + +static void check_logindex(void) +{ + if(logindex >= MAX_LOG_SIZE) + { + /* wrap */ + logdump(true); + //logwrap = true; + logindex = 0; + } +} + +static int log_push(void *userp, int c) +{ + (void)userp; + + logbuffer[logindex++] = c; + check_logindex(); + + return 1; +} + +/* our logf function */ +static void _log(const char *fmt, ...) +{ + if (!logenabled) + { + rb->splash(10, "log not enabled"); + return; + } + + + #ifdef USB_ENABLE_SERIAL + int old_logindex = logindex; + #endif + va_list ap; + + va_start(ap, fmt); + +#if (CONFIG_PLATFORM & PLATFORM_HOSTED) + char buf[1024]; + vsnprintf(buf, sizeof buf, fmt, ap); + DEBUGF("%s\n", buf); + /* restart va_list otherwise the result if undefined when vuprintf is called */ + va_end(ap); + va_start(ap, fmt); +#endif + + rb->vuprintf(log_push, NULL, fmt, ap); + va_end(ap); + + /* add trailing zero */ + log_push(NULL, '\0'); +} + + +int compute_nb_lines(int w, struct font* font) +{ + int i, nb_lines; + int cur_x, delta_x; + + if(logindex>= MAX_LOG_SIZE || (logindex == 0 && !logwrap)) + return 0; + + if(logwrap) + i = logindex; + else + i = 0; + + cur_x = 0; + nb_lines = 0; + + do { + if(logbuffer[i] == '\0') + { + cur_x = 0; + nb_lines++; + } + else + { + /* does character fit on this line ? */ + delta_x = rb->font_get_width(font, logbuffer[i]); + + if(cur_x + delta_x > w) + { + cur_x = 0; + nb_lines++; + } + + /* update pointer */ + cur_x += delta_x; + } + + i++; + if(i >= MAX_LOG_SIZE) + i = 0; + } while(i != logindex); + + return nb_lines; +} + +static bool logdisplay(void) +{ + + int w, h, i, index; + int fontnr; + static int delta_y = -1; + int cur_x, cur_y, delta_x; + struct font* font; + + char buf[2]; + + fontnr = FONT_FIRSTUSERFONT; + font = rb->font_get(fontnr); + buf[1] = '\0'; + w = LCD_WIDTH; + h = LCD_HEIGHT; + + if (delta_y < 0) /* init, get the horizontal size of each line */ + { + rb->font_getstringsize("A", NULL, &delta_y, fontnr); + /* start at the end of the log */ + gThread.user_index = compute_nb_lines(w, font) - h/delta_y -1; + /* user_index will be number of the first line to display (warning: line!=log entry) */ + /* if negative, will be set 0 to zero later */ + } + + + rb->lcd_clear_display(); + + if(gThread.user_index < 0 || gThread.user_index >= MAX_LOG_SIZE) + gThread.user_index = 0; + + + if(logwrap) + i = logindex; + else + i = 0; + + index = 0; + cur_x = 0; + cur_y = 0; + + /* nothing to print ? */ + if(logindex == 0 && !logwrap) + goto end_print; + + do { + if(logbuffer[i] == '\0') + { + /* should be display a newline ? */ + if(index >= gThread.user_index) + cur_y += delta_y; + cur_x = 0; + index++; + } + else + { + /* does character fit on this line ? */ + delta_x = rb->font_get_width(font, logbuffer[i]); + + if(cur_x + delta_x > w) + { + /* should be display a newline ? */ + if(index >= gThread.user_index) + cur_y += delta_y; + cur_x = 0; + index++; + } + + /* should we print character ? */ + if(index >= gThread.user_index) + { + buf[0] = logbuffer[i]; + rb->lcd_putsxy(cur_x, cur_y, buf); + } + + /* update pointer */ + cur_x += delta_x; + } + i++; + /* did we fill the screen ? */ + if(cur_y > h - delta_y) + { + if (TIME_AFTER(current_tick, gThread.last_useraction_tick + HZ)) + gThread.user_index++; + break; + } + + if(i >= MAX_LOG_SIZE) + i = 0; + } while(i != logindex); + + end_print: + rb->lcd_update(); + + return false; +} + +static bool logdump(bool append) +{ + int fd; + int flags = O_CREAT|O_WRONLY|O_TRUNC; + /* nothing to print ? */ + if(!logenabled || (logindex == 0 && !logwrap)) + { + /* nothing is logged just yet */ + return false; + } + if (!append) + { + flags = O_CREAT|O_WRONLY|O_APPEND; + } + + fd = open(ROCKBOX_DIR "/db_commit_log.txt", flags, 0666); + logenabled = false; + if(-1 != fd) { + int i; + + if(logwrap) + i = logindex; + else + i = 0; + + do { + if(logbuffer[i]=='\0') + rb->fdprintf(fd, "\n"); + else + rb->fdprintf(fd, "%c", logbuffer[i]); + + i++; + if(i >= MAX_LOG_SIZE) + i = 0; + } while(i != logindex); + + close(fd); + } + + logenabled = true; + + return false; +} + +static void allocate_tempbuf(void) +{ + tempbuf_size = 0; + tempbuf = rb->plugin_get_audio_buffer(&tempbuf_size); + tempbuf_size &= ~0x03; + +} + +static void free_tempbuf(void) +{ + if (tempbuf_size == 0) + return ; + + rb->plugin_release_audio_buffer(); + tempbuf = NULL; + tempbuf_size = 0; +} + +static bool do_timed_yield(void) +{ + /* Sorting can lock up for quite a while, so yield occasionally */ + static long wakeup_tick = 0; + if (TIME_AFTER(current_tick, wakeup_tick)) + { + + yield(); + + wakeup_tick = current_tick + (HZ/5); + return true; + } + return false; +} + +/*-----------------------------------------------------------------------------*/ +/******* plugin_start ******* */ +/*-----------------------------------------------------------------------------*/ + +enum plugin_status plugin_start(const void* parameter) +{ + (void) parameter; + + /* Turn off backlight timeout */ + backlight_ignore_timeout(); + + memset(&tc_stat, 0, sizeof(struct tagcache_stat)); + memset(¤t_tcmh, 0, sizeof(struct master_header)); + filenametag_fd = -1; + + strlcpy(tc_stat.db_path, rb->global_settings->tagcache_db_path, sizeof(tc_stat.db_path)); + if (!rb->dir_exists(tc_stat.db_path)) /* on fail use default DB path */ + strlcpy(tc_stat.db_path, ROCKBOX_DIR, sizeof(tc_stat.db_path)); + tc_stat.initialized = true; + + memset(&gThread, 0, sizeof(gThread)); + logf("started"); + logdump(false); + + thread_create(); + gThread.user_index = 0; + logdisplay(); /* get something on the screen while user waits */ + + allocate_tempbuf(); + + commit(); + + if (tc_stat.ready) + rb->tagcache_commit_finalize(); + + free_tempbuf(); + + logdump(true); + gThread.user_index++; + logdisplay(); + rb->thread_wait(gThread.id); + rb->queue_delete(&gThread.queue); + + /* Turn on backlight timeout (revert to settings) */ + backlight_use_settings(); + return PLUGIN_OK; +} + +/****************** main thread + helper ******************/ +static void thread(void) +{ + struct queue_event ev; + while (!gThread.exiting) + { + rb->queue_wait_w_tmo(&gThread.queue, &ev, 1); + switch (ev.id) + { + case SYS_USB_CONNECTED: + rb->usb_acknowledge(SYS_USB_CONNECTED_ACK); + logenabled = false; + break; + case SYS_USB_DISCONNECTED: + logenabled = true; + /*fall through*/ + case EV_STARTUP: + logf("Thread Started"); + break; + case EV_EXIT: + return; + default: + break; + } + logdisplay(); + + int action = rb->get_action(CONTEXT_STD, HZ/10); + + switch( action ) + { + case ACTION_NONE: + break; + case ACTION_STD_NEXT: + case ACTION_STD_NEXTREPEAT: + gThread.last_useraction_tick = current_tick; + gThread.user_index++; + break; + case ACTION_STD_PREV: + case ACTION_STD_PREVREPEAT: + gThread.last_useraction_tick = current_tick; + gThread.user_index--; + break; + case ACTION_STD_OK: + gThread.last_useraction_tick = current_tick; + gThread.user_index = 0; + break; + case SYS_POWEROFF: + case ACTION_STD_CANCEL: + gThread.exiting = true; + return; +#ifdef HAVE_TOUCHSCREEN + case ACTION_TOUCHSCREEN: + { + gThread.last_useraction_tick = current_tick; + short x, y; + static int prev_y; + + action = action_get_touchscreen_press(&x, &y); + + if(action & BUTTON_REL) + prev_y = 0; + else + { + if(prev_y != 0) + gThread.user_index += (prev_y - y) / delta_y; + + prev_y = y; + } + } +#endif + default: + break; + } + + + yield(); + } +} + +static void thread_create(void) +{ + /* put the thread's queue in the bcast list */ + rb->queue_init(&gThread.queue, true); + /*Note: tagcache_stack is defined in apps/tagcache.c */ + gThread.last_useraction_tick = current_tick; + gThread.id = rb->create_thread(thread, tagcache_stack, sizeof(tagcache_stack), + 0, "db_commit" + IF_PRIO(, PRIORITY_USER_INTERFACE) + IF_COP(, CPU)); + rb->queue_post(&gThread.queue, EV_STARTUP, 0); + yield(); +} diff --git a/apps/plugins/tagcache/tagcache.h b/apps/plugins/tagcache/tagcache.h new file mode 100644 index 0000000000..e416289741 --- /dev/null +++ b/apps/plugins/tagcache/tagcache.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef _TC_PLUGIN_ +#define _TC_PLUGIN_ +#endif /*_TC_PLUGIN_ */ + + diff --git a/apps/plugins/tagcache/tagcache.make b/apps/plugins/tagcache/tagcache.make new file mode 100644 index 0000000000..5d6d65cb0e --- /dev/null +++ b/apps/plugins/tagcache/tagcache.make @@ -0,0 +1,30 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +TCPLUG_SRCDIR := $(APPSDIR)/plugins/tagcache +TCPLUG_BUILDDIR := $(BUILDDIR)/apps/plugins/tagcache + +ROCKS += $(TCPLUG_BUILDDIR)/db_commit.rock + +TCPLUG_FLAGS = $(PLUGINFLAGS) -fno-strict-aliasing -Wno-unused \ + -I$(TCPLUG_SRCDIR) -ffunction-sections \ + -fdata-sections -Wl,--gc-sections +TCPLUG_SRC := $(call preprocess, $(TCPLUG_SRCDIR)/SOURCES) +TCPLUG_OBJ := $(call c2obj, $(TCPLUG_SRC)) + +# add source files to OTHER_SRC to get automatic dependencies +OTHER_SRC += $(APPSDIR)/tagcache.c $(TCPLUG_SRC) + +$(TCPLUG_BUILDDIR)/db_commit.rock: $(TCPLUG_OBJ) + +# special pattern rule for compiling with extra flags +$(TCPLUG_BUILDDIR)/%.o: $(TCPLUG_SRCDIR)/%.c $(TCPLUG_SRCDIR)/tagcache.make + $(SILENT)mkdir -p $(dir $@) + $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(TCPLUG_FLAGS) -c $< -o $@ + diff --git a/apps/tagcache.c b/apps/tagcache.c index 170a066a36..b0c2eac28f 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -55,6 +55,7 @@ * */ +#if !defined(PLUGIN) /*#define LOGF_ENABLE*/ /*#define LOGF_CLAUSES define to enable logf clause matching (LOGF_ENABLE req'd) */ @@ -91,7 +92,7 @@ #include "lang.h" #include "eeprom_settings.h" #endif - +#endif /*!defined(PLUGIN)*/ /* * Define this to support non-native endian tagcache files. * Databases are always written in native endian so this is @@ -132,6 +133,9 @@ /* Idle time before committing events in the command queue. */ #define TAGCACHE_COMMAND_QUEUE_COMMIT_DELAY HZ*2 +/* Dont commit database_tmp data. */ +#define TAGCACHE_FILE_NOCOMMIT "database_commit.ignore" + /* Temporary database containing new tags to be committed to the main db. */ #define TAGCACHE_FILE_TEMP "database_tmp.tcd" @@ -730,7 +734,7 @@ static bool update_master_header(void) return true; } - +#if !defined(PLUGIN) #ifndef __PCTOOL__ static bool do_timed_yield(void) { @@ -2355,6 +2359,8 @@ static void NO_INLINE add_tagcache(char *path, unsigned long mtime) #undef ADD_TAG } +#endif /*!defined(PLUGIN)*/ + static bool tempbuf_insert(char *str, int id, int idx_id, bool unique) { @@ -3064,18 +3070,22 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd) } str_setlen(build_idx_buf, entry.tag_length[index_type]); - if (TAGCACHE_IS_UNIQUE(index_type)) - error = !tempbuf_insert(build_idx_buf, i, -1, true); - else - error = !tempbuf_insert(build_idx_buf, i, - tcmh.tch.entry_count + i, false); - - if (error) +#if defined(PLUGIN) + if (user_check_tag(index_type, build_idx_buf)) +#endif /*defined(PLUGIN)*/ { - logf("insert error"); - goto error_exit; - } + if (TAGCACHE_IS_UNIQUE(index_type)) + error = !tempbuf_insert(build_idx_buf, i, -1, true); + else + error = !tempbuf_insert(build_idx_buf, i, + tcmh.tch.entry_count + i, false); + if (error) + { + logf("insert error"); + goto error_exit; + } + } /* Skip to next. */ lseek(tmpfd, entry.data_length - entry.tag_offset[index_type] - entry.tag_length[index_type], SEEK_CUR); @@ -3299,7 +3309,20 @@ static bool commit(void) while (write_lock) sleep(1); - tmpfd = open_db_fd(TAGCACHE_FILE_TEMP, O_RDONLY); +#if !defined(PLUGIN) + int fd = open_db_fd(TAGCACHE_FILE_NOCOMMIT, O_RDONLY); + if (fd >= 0) + { + logf("canceling commit"); + tc_stat.commit_delayed = true; + close(fd); + tmpfd = -1; + } + else +#endif /*!defined(PLUGIN)*/ + { + tmpfd = open_db_fd(TAGCACHE_FILE_TEMP, O_RDONLY); + } if (tmpfd < 0) { logf("nothing to commit"); @@ -3361,6 +3384,14 @@ static bool commit(void) } #endif /* HAVE_TC_RAMCACHE */ +#if defined(PLUGIN) + if (tempbuf_size == 0) + { + tempbuf = rb->plugin_get_audio_buffer(&tempbuf_size); + tempbuf_size &= ~0x03; + } +#endif /*defined(PLUGIN)*/ + /* And finally fail if there are no buffers available. */ if (tempbuf_size == 0) { @@ -3433,8 +3464,7 @@ static bool commit(void) close(masterfd); logf("tagcache committed"); - tc_stat.ready = check_all_headers(); - tc_stat.readyvalid = true; + tagcache_commit_finalize(); #if defined(HAVE_TC_RAMCACHE) if (ramcache_buffer_stolen) @@ -3476,7 +3506,13 @@ commit_error: return rc; } +void tagcache_commit_finalize(void) +{ + tc_stat.ready = check_all_headers(); + tc_stat.readyvalid = true; +} +#if !defined(PLUGIN) #ifndef __PCTOOL__ static bool modify_numeric_entry(int masterfd, int idx_id, int tag, long data) @@ -5116,8 +5152,7 @@ static void tagcache_thread(void) if (!tc_stat.ready) { sleep(HZ); - tc_stat.ready = check_all_headers(); - tc_stat.readyvalid = true; + tagcache_commit_finalize(); } while (1) @@ -5351,3 +5386,4 @@ int tagcache_get_max_commit_step(void) { return (int)(SORTED_TAGS_COUNT)+1; } +#endif /*!defined(PLUGIN)*/ diff --git a/apps/tagcache.h b/apps/tagcache.h index 9cf796fafd..a20a13900a 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -204,6 +204,7 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename); #endif void tagcache_unload_ramcache(void); #endif +void tagcache_commit_finalize(void); void tagcache_init(void) INIT_ATTR; bool tagcache_is_initialized(void); bool tagcache_is_fully_initialized(void); diff --git a/manual/rockbox_interface/tagcache.tex b/manual/rockbox_interface/tagcache.tex index 3fae3c5c04..a0d9834779 100644 --- a/manual/rockbox_interface/tagcache.tex +++ b/manual/rockbox_interface/tagcache.tex @@ -31,6 +31,15 @@ If a subdirectory of an `ignored' directory should still be scanned, place a file named \fname{database.unignore} in it. The files in that directory and its subdirectories will be scanned and added to the database. +\subsubsection{Issues During Database Commit} + +You may have files on your \dap{} whose contents might not be displayed +correctly or even crash the database. +Placing a file named \fname{/.rockbox/database_commit.ignore} +will prevent the device from committing the database automatically +you can manually commit the database using the db_commit plugin in APPS +with logging + \subsection{\label{ref:databasemenu}The Database Menu} \begin{description} -- cgit v1.2.3