Rewrite global cache handling code in fontconfig to eliminate per-file

syscalls
This commit is contained in:
Keith Packard 2002-07-28 10:50:59 +00:00
parent 23cd70c4ef
commit 327a7fd491
6 changed files with 852 additions and 506 deletions

View File

@ -191,7 +191,7 @@ typedef enum { FcEndianBig, FcEndianLittle } FcEndian;
typedef struct _FcConfig FcConfig; typedef struct _FcConfig FcConfig;
typedef struct _FcFileCache FcFileCache; typedef struct _FcGlobalCache FcFileCache;
typedef struct _FcBlanks FcBlanks; typedef struct _FcBlanks FcBlanks;
@ -365,9 +365,6 @@ FcDirScan (FcFontSet *set,
FcBool FcBool
FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir); FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir);
FcBool
FcDirCacheValid (const FcChar8 *dir);
/* fcfreetype.c */ /* fcfreetype.c */
FcPattern * FcPattern *
FcFreeTypeQuery (const FcChar8 *file, int id, FcBlanks *blanks, int *count); FcFreeTypeQuery (const FcChar8 *file, int id, FcBlanks *blanks, int *count);

File diff suppressed because it is too large Load Diff

View File

@ -171,20 +171,20 @@ FcConfigDestroy (FcConfig *config)
FcBool FcBool
FcConfigBuildFonts (FcConfig *config) FcConfigBuildFonts (FcConfig *config)
{ {
FcFontSet *fonts; FcFontSet *fonts;
FcFileCache *cache; FcGlobalCache *cache;
FcStrList *list; FcStrList *list;
FcChar8 *dir; FcChar8 *dir;
fonts = FcFontSetCreate (); fonts = FcFontSetCreate ();
if (!fonts) if (!fonts)
goto bail0; goto bail0;
cache = FcFileCacheCreate (); cache = FcGlobalCacheCreate ();
if (!cache) if (!cache)
goto bail1; goto bail1;
FcFileCacheLoad (cache, config->cache); FcGlobalCacheLoad (cache, config->cache);
list = FcConfigGetFontDirs (config); list = FcConfigGetFontDirs (config);
if (!list) if (!list)
@ -202,8 +202,8 @@ FcConfigBuildFonts (FcConfig *config)
if (FcDebug () & FC_DBG_FONTSET) if (FcDebug () & FC_DBG_FONTSET)
FcFontSetPrint (fonts); FcFontSetPrint (fonts);
FcFileCacheSave (cache, config->cache); FcGlobalCacheSave (cache, config->cache);
FcFileCacheDestroy (cache); FcGlobalCacheDestroy (cache);
FcConfigSetFonts (config, fonts, FcSetSystem); FcConfigSetFonts (config, fonts, FcSetSystem);
@ -456,8 +456,6 @@ typedef struct _FcSubState {
FcValueList *value; FcValueList *value;
} FcSubState; } FcSubState;
static const FcMatrix FcIdentityMatrix = { 1, 0, 0, 1 };
static FcValue static FcValue
FcConfigPromote (FcValue v, FcValue u) FcConfigPromote (FcValue v, FcValue u)
{ {
@ -468,9 +466,8 @@ FcConfigPromote (FcValue v, FcValue u)
} }
else if (v.type == FcTypeVoid && u.type == FcTypeMatrix) else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
{ {
v.u.m = FcMatrixCopy (&FcIdentityMatrix); v.u.m = &FcIdentityMatrix;
if (v.u.m) v.type = FcTypeMatrix;
v.type = FcTypeMatrix;
} }
return v; return v;
} }

View File

@ -38,44 +38,71 @@ FcFileIsDir (const FcChar8 *file)
FcBool FcBool
FcFileScan (FcFontSet *set, FcFileScan (FcFontSet *set,
FcStrSet *dirs, FcStrSet *dirs,
FcFileCache *cache, FcGlobalCache *cache,
FcBlanks *blanks, FcBlanks *blanks,
const FcChar8 *file, const FcChar8 *file,
FcBool force) FcBool force)
{ {
int id; int id;
FcChar8 *name; FcChar8 *name;
FcPattern *font; FcPattern *font;
FcBool ret = FcTrue; FcBool ret = FcTrue;
FcBool isDir; FcBool isDir;
int count; int count = 0;
FcGlobalCacheFile *cache_file;
FcGlobalCacheDir *cache_dir;
FcBool need_scan;
if (force)
cache = 0;
id = 0; id = 0;
do do
{ {
if (!force && cache) need_scan = FcTrue;
name = FcFileCacheFind (cache, file, id, &count); font = 0;
else /*
name = 0; * Check the cache
if (name) */
if (cache)
{ {
/* "." means the file doesn't contain a font */ if ((cache_file = FcGlobalCacheFileGet (cache, file, id, &count)))
if (FcStrCmp (name, FC_FONT_FILE_INVALID) == 0)
font = 0;
else if (FcStrCmp (name, FC_FONT_FILE_DIR) == 0)
{ {
ret = FcStrSetAdd (dirs, file); /*
font = 0; * Found a cache entry for the file
*/
if (FcGlobalCacheCheckTime (&cache_file->info))
{
name = cache_file->name;
need_scan = FcFalse;
FcGlobalCacheReferenced (cache, &cache_file->info);
/* "." means the file doesn't contain a font */
if (FcStrCmp (name, FC_FONT_FILE_INVALID) != 0)
{
font = FcNameParse (name);
if (font)
if (!FcPatternAddString (font, FC_FILE, file))
ret = FcFalse;
}
}
} }
else else if ((cache_dir = FcGlobalCacheDirGet (cache, file,
strlen ((const char *) file),
FcFalse)))
{ {
font = FcNameParse (name); if (FcGlobalCacheCheckTime (&cache_dir->info))
if (font) {
if (!FcPatternAddString (font, FC_FILE, file)) font = 0;
need_scan = FcFalse;
FcGlobalCacheReferenced (cache, &cache_dir->info);
if (!FcStrSetAdd (dirs, file))
ret = FcFalse; ret = FcFalse;
}
} }
} }
else /*
* Nothing in the cache, scan the file
*/
if (need_scan)
{ {
if (FcDebug () & FC_DBG_SCAN) if (FcDebug () & FC_DBG_SCAN)
{ {
@ -91,35 +118,24 @@ FcFileScan (FcFontSet *set,
isDir = FcTrue; isDir = FcTrue;
ret = FcStrSetAdd (dirs, file); ret = FcStrSetAdd (dirs, file);
} }
if (!force && cache) /*
* Update the cache
*/
if (cache && font)
{ {
if (font) FcChar8 *unparse;
{
FcChar8 *unparse;
unparse = FcNameUnparse (font); unparse = FcNameUnparse (font);
if (unparse) if (unparse)
{
(void) FcFileCacheUpdate (cache, file, id, unparse);
free (unparse);
}
}
else
{ {
if (isDir) (void) FcGlobalCacheUpdate (cache, file, id, unparse);
{ free (unparse);
FcFileCacheUpdate (cache, file, id, (FcChar8 *)
FC_FONT_FILE_DIR);
}
else
{
/* negative cache files not containing fonts */
FcFileCacheUpdate (cache, file, id, (FcChar8 *)
FC_FONT_FILE_INVALID);
}
} }
} }
} }
/*
* Add the font
*/
if (font) if (font)
{ {
if (!FcFontSetAdd (set, font)) if (!FcFontSetAdd (set, font))
@ -134,40 +150,37 @@ FcFileScan (FcFontSet *set,
return ret; return ret;
} }
FcBool
FcDirCacheValid (const FcChar8 *dir)
{
FcChar8 *path;
FcBool ret;
path = (FcChar8 *) malloc (strlen ((const char *) dir) + 1 +
strlen ((const char *) FC_DIR_CACHE_FILE) + 1);
if (!path)
return FcFalse;
strcpy ((char *) path, (const char *) dir);
strcat ((char *) path, (const char *) "/");
strcat ((char *) path, (const char *) FC_DIR_CACHE_FILE);
ret = FcFileCacheValid (path);
free (path);
return ret;
}
#define FC_MAX_FILE_LEN 4096 #define FC_MAX_FILE_LEN 4096
FcBool FcBool
FcDirScan (FcFontSet *set, FcDirScan (FcFontSet *set,
FcStrSet *dirs, FcStrSet *dirs,
FcFileCache *cache, FcGlobalCache *cache,
FcBlanks *blanks, FcBlanks *blanks,
const FcChar8 *dir, const FcChar8 *dir,
FcBool force) FcBool force)
{ {
DIR *d; DIR *d;
struct dirent *e; struct dirent *e;
FcChar8 *file; FcChar8 *file;
FcChar8 *base; FcChar8 *base;
FcBool ret = FcTrue; FcBool ret = FcTrue;
if (!force)
{
/*
* Check fonts.cache file
*/
if (FcDirCacheReadDir (set, dirs, dir))
return FcTrue;
/*
* Check ~/.fonts.cache file
*/
if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir))
return FcTrue;
}
file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
if (!file) if (!file)
return FcFalse; return FcFalse;
@ -175,18 +188,9 @@ FcDirScan (FcFontSet *set,
strcpy ((char *) file, (char *) dir); strcpy ((char *) file, (char *) dir);
strcat ((char *) file, "/"); strcat ((char *) file, "/");
base = file + strlen ((char *) file); base = file + strlen ((char *) file);
if (!force)
{
strcpy ((char *) base, FC_DIR_CACHE_FILE);
if (FcFileCacheReadDir (set, dirs, file))
{
free (file);
return FcTrue;
}
}
d = opendir ((char *) dir); d = opendir ((char *) dir);
if (!d) if (!d)
{ {
free (file); free (file);
@ -205,25 +209,14 @@ FcDirScan (FcFontSet *set,
} }
free (file); free (file);
closedir (d); closedir (d);
if (ret && cache)
FcGlobalCacheUpdate (cache, dir, 0, 0);
return ret; return ret;
} }
FcBool FcBool
FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir) FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
{ {
FcChar8 *file; return FcDirCacheWriteDir (set, dirs, dir);
FcChar8 *base;
FcBool ret;
file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + 256 + 1);
if (!file)
return FcFalse;
strcpy ((char *) file, (char *) dir);
strcat ((char *) file, "/");
base = file + strlen ((char *) file);
strcpy ((char *) base, FC_DIR_CACHE_FILE);
ret = FcFileCacheWriteDir (set, dirs, file);
free (file);
return ret;
} }

View File

@ -195,24 +195,53 @@ typedef struct _FcStrBuf {
int size; int size;
} FcStrBuf; } FcStrBuf;
typedef struct _FcFileCacheEnt { /*
struct _FcFileCacheEnt *next; * The per-user ~/.fonts.cache file is loaded into
unsigned int hash; * this data structure. Each directory gets a substructure
FcChar8 *file; * which is validated by comparing the directory timestamp with
int id; * that saved in the cache. When valid, the entire directory cache
time_t time; * can be immediately loaded without reading the directory. Otherwise,
FcChar8 *name; * the files are checked individually; updated files are loaded into the
FcBool referenced; * cache which is then rewritten to the users home directory
} FcFileCacheEnt; */
#define FC_FILE_CACHE_HASH_SIZE 509 #define FC_GLOBAL_CACHE_DIR_HASH_SIZE 37
#define FC_GLOBAL_CACHE_FILE_HASH_SIZE 67
struct _FcFileCache { typedef struct _FcGlobalCacheInfo {
FcFileCacheEnt *ents[FC_FILE_CACHE_HASH_SIZE]; unsigned int hash;
FcBool updated; FcChar8 *file;
int entries; time_t time;
int referenced; FcBool referenced;
}; } FcGlobalCacheInfo;
typedef struct _FcGlobalCacheFile {
struct _FcGlobalCacheFile *next;
FcGlobalCacheInfo info;
int id;
FcChar8 *name;
} FcGlobalCacheFile;
typedef struct _FcGlobalCacheSubdir {
struct _FcGlobalCacheSubdir *next;
FcChar8 *file;
} FcGlobalCacheSubdir;
typedef struct _FcGlobalCacheDir {
struct _FcGlobalCacheDir *next;
FcGlobalCacheInfo info;
int len;
FcGlobalCacheFile *ents[FC_GLOBAL_CACHE_FILE_HASH_SIZE];
FcGlobalCacheSubdir *subdirs;
} FcGlobalCacheDir;
typedef struct _FcGlobalCache {
FcGlobalCacheDir *ents[FC_GLOBAL_CACHE_DIR_HASH_SIZE];
FcBool updated;
FcBool broken;
int entries;
int referenced;
} FcGlobalCache;
struct _FcAtomic { struct _FcAtomic {
FcChar8 *file; /* original file name */ FcChar8 *file; /* original file name */
@ -284,40 +313,60 @@ typedef struct _FcCharMap FcCharMap;
/* fccache.c */ /* fccache.c */
FcFileCache * FcGlobalCache *
FcFileCacheCreate (void); FcGlobalCacheCreate (void);
FcChar8 *
FcFileCacheFind (FcFileCache *cache,
const FcChar8 *file,
int id,
int *count);
void void
FcFileCacheDestroy (FcFileCache *cache); FcGlobalCacheDestroy (FcGlobalCache *cache);
FcBool FcBool
FcFileCacheValid (const FcChar8 *cache_file); FcGlobalCacheCheckTime (FcGlobalCacheInfo *info);
void void
FcFileCacheLoad (FcFileCache *cache, FcGlobalCacheReferenced (FcGlobalCache *cache,
const FcChar8 *cache_file); FcGlobalCacheInfo *info);
FcGlobalCacheDir *
FcGlobalCacheDirGet (FcGlobalCache *cache,
const FcChar8 *dir,
int len,
FcBool create_missing);
FcBool FcBool
FcFileCacheUpdate (FcFileCache *cache, FcGlobalCacheScanDir (FcFontSet *set,
const FcChar8 *file, FcStrSet *dirs,
int id, FcGlobalCache *cache,
const FcChar8 *name); const FcChar8 *dir);
FcGlobalCacheFile *
FcGlobalCacheFileGet (FcGlobalCache *cache,
const FcChar8 *file,
int id,
int *count);
void
FcGlobalCacheLoad (FcGlobalCache *cache,
const FcChar8 *cache_file);
FcBool FcBool
FcFileCacheSave (FcFileCache *cache, FcGlobalCacheUpdate (FcGlobalCache *cache,
const FcChar8 *cache_file); const FcChar8 *file,
int id,
const FcChar8 *name);
FcBool FcBool
FcFileCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *cache_file); FcGlobalCacheSave (FcGlobalCache *cache,
const FcChar8 *cache_file);
FcBool FcBool
FcFileCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *cache_file); FcDirCacheValid (const FcChar8 *cache_file);
FcBool
FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir);
FcBool
FcDirCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir);
/* fccfg.c */ /* fccfg.c */
@ -523,6 +572,9 @@ FcPatternAddWithBinding (FcPattern *p,
/* fcrender.c */ /* fcrender.c */
/* fcmatrix.c */ /* fcmatrix.c */
extern const FcMatrix FcIdentityMatrix;
void void
FcMatrixFree (FcMatrix *mat); FcMatrixFree (FcMatrix *mat);

View File

@ -27,6 +27,8 @@
#include <ctype.h> #include <ctype.h>
#include "fcint.h" #include "fcint.h"
const FcMatrix FcIdentityMatrix = { 1, 0, 0, 1 };
FcMatrix * FcMatrix *
FcMatrixCopy (const FcMatrix *mat) FcMatrixCopy (const FcMatrix *mat)
{ {
@ -44,8 +46,11 @@ FcMatrixCopy (const FcMatrix *mat)
void void
FcMatrixFree (FcMatrix *mat) FcMatrixFree (FcMatrix *mat)
{ {
FcMemFree (FC_MEM_MATRIX, sizeof (FcMatrix)); if (mat != &FcIdentityMatrix)
free (mat); {
FcMemFree (FC_MEM_MATRIX, sizeof (FcMatrix));
free (mat);
}
} }
FcBool FcBool