diff options
author | Akira TAGOH <akira@tagoh.org> | 2015-08-14 17:17:34 +0900 |
---|---|---|
committer | Akira TAGOH <akira@tagoh.org> | 2015-08-14 17:19:29 +0900 |
commit | ad9f5880502c9a3f8e7f8919336888ee056f17ba (patch) | |
tree | d5d0ad4e90499856f056c720ad962a080042e2cd /src | |
parent | 46ec6a52d4cc447cc3ff4a13b2067ecb76c9db2e (diff) |
Fix the broken cache more.
Take a look at the nano second in the mtime to figure out
if the cache needs to be updated if available.
and do the mutex lock between scanning and writing a cache
to avoid the conflict.
Also we don't need to scan directories again after writing
caches. so getting rid of the related code as well.
https://bugs.freedesktop.org/show_bug.cgi?id=69845
and for reference:
https://bugzilla.redhat.com/show_bug.cgi?id=1236034
Diffstat (limited to 'src')
-rw-r--r-- | src/fcarch.c | 2 | ||||
-rw-r--r-- | src/fccache.c | 98 | ||||
-rw-r--r-- | src/fcdir.c | 6 | ||||
-rw-r--r-- | src/fcint.h | 8 |
4 files changed, 112 insertions, 2 deletions
diff --git a/src/fcarch.c b/src/fcarch.c index 4a921c06..da33a83d 100644 --- a/src/fcarch.c +++ b/src/fcarch.c @@ -48,7 +48,7 @@ FC_ASSERT_STATIC (0x08 + 1*FC_MAX(SIZEOF_VOID_P,ALIGNOF_DOUBLE) == sizeof (FcVal FC_ASSERT_STATIC (0x00 + 2*SIZEOF_VOID_P == sizeof (FcPatternElt)); FC_ASSERT_STATIC (0x08 + 2*SIZEOF_VOID_P == sizeof (FcPattern)); FC_ASSERT_STATIC (0x08 + 2*SIZEOF_VOID_P == sizeof (FcCharSet)); -FC_ASSERT_STATIC (0x08 + 6*SIZEOF_VOID_P == sizeof (FcCache)); +FC_ASSERT_STATIC (0x08 + 7*SIZEOF_VOID_P == sizeof (FcCache)); int diff --git a/src/fccache.c b/src/fccache.c index fc3ed410..20c44180 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -253,6 +253,7 @@ struct _FcCacheSkip { dev_t cache_dev; ino_t cache_ino; time_t cache_mtime; + long cache_mtime_nano; FcCacheSkip *next[1]; }; @@ -380,12 +381,18 @@ FcCacheInsert (FcCache *cache, struct stat *cache_stat) s->cache_dev = cache_stat->st_dev; s->cache_ino = cache_stat->st_ino; s->cache_mtime = cache_stat->st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIM + s->cache_mtime_nano = cache_stat->st_mtim.tv_nsec; +#else + s->cache_mtime_nano = 0; +#endif } else { s->cache_dev = 0; s->cache_ino = 0; s->cache_mtime = 0; + s->cache_mtime_nano = 0; } /* @@ -473,6 +480,10 @@ FcCacheFindByStat (struct stat *cache_stat) s->cache_ino == cache_stat->st_ino && s->cache_mtime == cache_stat->st_mtime) { +#ifdef HAVE_STRUCT_STAT_ST_MTIM + if (s->cache_mtime != cache_stat->st_mtim.tv_nsec) + continue; +#endif FcRefInc (&s->ref); unlock_cache (); return s->cache; @@ -540,6 +551,7 @@ static FcBool FcCacheTimeValid (FcConfig *config, FcCache *cache, struct stat *dir_stat) { struct stat dir_static; + FcBool fnano = FcTrue; if (!dir_stat) { @@ -558,10 +570,18 @@ FcCacheTimeValid (FcConfig *config, FcCache *cache, struct stat *dir_stat) FcStrFree (d); dir_stat = &dir_static; } +#ifdef HAVE_STRUCT_STAT_ST_MTIM + fnano = (cache->checksum_nano == dir_stat->st_mtim.tv_nsec); + if (FcDebug () & FC_DBG_CACHE) + printf ("FcCacheTimeValid dir \"%s\" cache checksum %d.%ld dir checksum %d.%ld\n", + FcCacheDir (cache), cache->checksum, cache->checksum_nano, (int) dir_stat->st_mtime, dir_stat->st_mtim.tv_nsec); +#else if (FcDebug () & FC_DBG_CACHE) printf ("FcCacheTimeValid dir \"%s\" cache checksum %d dir checksum %d\n", FcCacheDir (cache), cache->checksum, (int) dir_stat->st_mtime); - return cache->checksum == (int) dir_stat->st_mtime; +#endif + + return cache->checksum == (int) dir_stat->st_mtime && fnano; } static FcBool @@ -757,6 +777,10 @@ FcDirCacheValidateHelper (FcConfig *config, int fd, struct stat *fd_stat, struct ret = FcFalse; else if (c.checksum != (int) dir_stat->st_mtime) ret = FcFalse; +#ifdef HAVE_STRUCT_STAT_ST_MTIM + else if (c.checksum_nano != dir_stat->st_mtim.tv_nsec) + ret = FcFalse; +#endif return ret; } @@ -831,6 +855,9 @@ FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcSt cache->version = FC_CACHE_VERSION_NUMBER; cache->size = serialize->size; cache->checksum = (int) dir_stat->st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIM + cache->checksum_nano = dir_stat->st_mtim.tv_nsec; +#endif /* * Serialize directory name @@ -1018,6 +1045,11 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config) skip->cache_dev = cache_stat.st_dev; skip->cache_ino = cache_stat.st_ino; skip->cache_mtime = cache_stat.st_mtime; +#ifdef HAVE_STRUCT_STAT_ST_MTIM + skip->cache_mtime_nano = cache_stat.st_mtim.tv_nsec; +#else + skip->cache_mtime_nano = 0; +#endif } unlock_cache (); } @@ -1142,6 +1174,70 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) return ret; } +int +FcDirCacheLock (const FcChar8 *dir, + FcConfig *config) +{ + FcChar8 *cache_hashed = NULL; + FcChar8 cache_base[CACHEBASE_LEN]; + FcStrList *list; + FcChar8 *cache_dir; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + int fd = -1; + + FcDirCacheBasename (dir, cache_base); + list = FcStrListCreate (config->cacheDirs); + if (!list) + return -1; + + while ((cache_dir = FcStrListNext (list))) + { + if (sysroot) + cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL); + else + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); + if (!cache_hashed) + break; + fd = FcOpen ((const char *)cache_hashed, O_RDWR); + /* No caches in that directory. simply retry with another one */ + if (fd != -1) + { + struct flock fl; + + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid (); + if (fcntl (fd, F_SETLKW, &fl) == -1) + goto bail; + break; + } + } + return fd; +bail: + if (fd != -1) + close (fd); + return -1; +} + +void +FcDirCacheUnlock (int fd) +{ + struct flock fl; + + if (fd != -1) + { + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid (); + fcntl (fd, F_SETLK, &fl); + close (fd); + } +} + /* * Hokey little macro trick to permit the definitions of C functions * with the same name as CPP macros diff --git a/src/fcdir.c b/src/fcdir.c index 2e7f0dc7..f4807dd6 100644 --- a/src/fcdir.c +++ b/src/fcdir.c @@ -332,6 +332,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) struct stat dir_stat; const FcChar8 *sysroot = FcConfigGetSysRoot (config); FcChar8 *d; + int fd = -1; if (sysroot) d = FcStrBuildFilename (sysroot, dir, NULL); @@ -352,6 +353,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) if (!dirs) goto bail1; + fd = FcDirCacheLock (dir, config); /* * Scan the dir */ @@ -371,6 +373,7 @@ FcDirCacheScan (const FcChar8 *dir, FcConfig *config) FcDirCacheWrite (cache, config); bail2: + FcDirCacheUnlock (fd); FcStrSetDestroy (dirs); bail1: FcFontSetDestroy (set); @@ -389,6 +392,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) FcStrSet *dirs; const FcChar8 *sysroot = FcConfigGetSysRoot (config); FcChar8 *d = NULL; + int fd = -1; cache = FcDirCacheLoad (dir, config, NULL); if (!cache) @@ -404,6 +408,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) if (!dirs) goto bail; + fd = FcDirCacheLock (dir, config); /* * Scan the dir */ @@ -422,6 +427,7 @@ FcDirCacheRescan (const FcChar8 *dir, FcConfig *config) FcDirCacheWrite (new, config); bail1: + FcDirCacheUnlock (fd); FcStrSetDestroy (dirs); bail: if (d) diff --git a/src/fcint.h b/src/fcint.h index 15e22fdb..68f98178 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -369,6 +369,7 @@ struct _FcCache { int dirs_count; /* number of subdir strings */ intptr_t set; /* offset to font set */ int checksum; /* checksum of directory state */ + long checksum_nano; /* checksum of directory state */ }; #undef FcCacheDir @@ -590,6 +591,13 @@ FcCacheFini (void); FcPrivate void FcDirCacheReference (FcCache *cache, int nref); +FcPrivate int +FcDirCacheLock (const FcChar8 *dir, + FcConfig *config); + +FcPrivate void +FcDirCacheUnlock (int fd); + /* fccfg.c */ FcPrivate FcBool |