FileCache.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:6k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: FileCache.c++,v 1.1.1.1 2005/11/11 21:32:03 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1995-1996 Sam Leffler
  4.  * Copyright (c) 1995-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "FileCache.h"
  27. #include "Sys.h"
  28. u_int FileCache::master = 0; // master serial number
  29. FileCache* FileCache::cache[4096]; // cache of stat results
  30. #define CACHESIZE (sizeof (cache) / sizeof (cache[0]))
  31. // statistics
  32. u_int FileCache::lookups = 0; // total # lookups
  33. u_int FileCache::hits = 0; // # lookups that hit in the cache
  34. u_int FileCache::probes = 0; // total # probes during lookups
  35. u_int FileCache::displaced = 0; // # entries reused
  36. u_int FileCache::flushed = 0; // # entries flushed
  37. void
  38. FileCache::printStats(FILE* fd)
  39. {
  40.     fprintf(fd, "    File cache: %u lookups, %u hits (%.1f%%), %.1f avg probesrn"
  41. , lookups
  42. , hits
  43. #define NZ(v) ((v) == 0 ? 1 : (v))
  44. , (100.*hits)/NZ(lookups)
  45. , float(lookups+probes)/float(NZ(lookups))
  46.     );
  47.     u_int n = 0;
  48.     u_int space = 0;
  49.     for (u_int i = 0; i < CACHESIZE; i++) {
  50. const FileCache* fi = cache[i];
  51. if (fi) {
  52.     n++;
  53.     space += sizeof (*fi) + fi->name.length();
  54. }
  55.     }
  56.     fprintf(fd, "        %u entries (%.1f KB), %u entries displaced, %u entries flushedrn"
  57. , n
  58. , space / 1024.
  59. , displaced
  60. , flushed
  61.     );
  62. }
  63. FileCache::FileCache() {}
  64. FileCache::~FileCache() {}
  65. void
  66. FileCache::reset(void)
  67. {
  68.     for (u_int i = 0; i < CACHESIZE; i++)
  69. delete cache[i];
  70.     memset(cache, 0, sizeof (cache));
  71.     master = 0; // doesn't matter???
  72. }
  73. u_int
  74. FileCache::hash(const char* pathname)
  75. {
  76.     u_int h = 0;
  77.     while (*pathname)
  78. h ^= *pathname++;
  79.     return (h % CACHESIZE);
  80. }
  81. bool
  82. FileCache::lookup(const char* pathname, struct stat& sb, bool addToCache)
  83. {
  84.     lookups++;
  85.     u_int h = hash(pathname);
  86.     u_int maxprobes = 5;
  87.     FileCache* fi = cache[h];
  88.     FileCache* oldest = fi;
  89.     while (fi && --maxprobes) {
  90. probes++;
  91. if (fi->name == pathname) {
  92.     fi->serial = master++;
  93.     sb = fi->sb;
  94.     hits++;
  95.     return (true);
  96. }
  97. if (fi->serial < oldest->serial)
  98.     oldest = fi;
  99. h = (u_int)(h*h) % CACHESIZE;
  100. fi = cache[h];
  101.     }
  102.     /*
  103.      * Pathname not found in the cache.
  104.      */
  105.     if (Sys::stat(pathname, sb) < 0)
  106. return (false);
  107.     if (addToCache && pathname[0] != '.') {
  108. if (fi) {
  109.     fi = oldest;
  110.     displaced++;
  111. } else
  112.     fi = cache[h] = new FileCache;
  113. fi->name = pathname;
  114. fi->serial = master++;
  115. fi->sb = sb;
  116.     }
  117.     return (true);
  118. }
  119. /*
  120.  * Update the file mode for any in-cache entry.
  121.  */
  122. bool
  123. FileCache::chmod(const char* pathname, mode_t mode)
  124. {
  125.     if (Sys::chmod(pathname, mode) < 0)
  126. return (false);
  127.     lookups++;
  128.     u_int h = hash(pathname);
  129.     u_int maxprobes = 5;
  130.     FileCache* fi = cache[h];
  131.     while (fi && --maxprobes) {
  132. probes++;
  133. if (fi->name == pathname) {
  134.     hits++;
  135.     fi->sb.st_mode = (fi->sb.st_mode&~0777) | (mode&0777);
  136.     break;
  137. }
  138. h = (u_int)(h*h) % CACHESIZE;
  139. fi = cache[h];
  140.     }
  141.     return (true);
  142. }
  143. /*
  144.  * Update the file ownership for any in-cache entry.
  145.  */
  146. bool
  147. FileCache::chown(const char* pathname, uid_t uid, gid_t gid)
  148. {
  149.     /*
  150.      * For BSD-based systems chown is only permitted
  151.      * by the super-user.  We could optimize this work
  152.      * to not swap the effective uid on System V-based
  153.      * systems but it's not worth it since the majority
  154.      * the calls to chown a file will be done only for
  155.      * BSD-based systems (to deal with the filesystem
  156.      * semantics forcing us to manually set the gid on
  157.      * newly created files.
  158.      */
  159.     uid_t ouid = geteuid();
  160.     (void) seteuid(0);
  161.     bool ok = (Sys::chown(pathname, uid, gid) >= 0);
  162.     (void) seteuid(ouid);
  163.     if (ok) {
  164. lookups++;
  165. u_int h = hash(pathname);
  166. u_int maxprobes = 5;
  167. FileCache* fi = cache[h];
  168. while (fi && --maxprobes) {
  169.     probes++;
  170.     if (fi->name == pathname) {
  171. hits++;
  172. fi->sb.st_uid = uid;
  173. fi->sb.st_gid = gid;
  174. break;
  175.     }
  176.     h = (u_int)(h*h) % CACHESIZE;
  177.     fi = cache[h];
  178. }
  179.     }
  180.     return (ok);
  181. }
  182. /*
  183.  * Like lookup, but if found in the cache, re-do the stat.
  184.  */
  185. bool
  186. FileCache::update(const char* pathname, struct stat& sb, bool addToCache)
  187. {
  188.     lookups++;
  189.     u_int h = hash(pathname);
  190.     u_int maxprobes = 5;
  191.     FileCache* fi = cache[h];
  192.     FileCache* oldest = fi;
  193.     while (fi && --maxprobes) {
  194. probes++;
  195. if (fi->name == pathname) {
  196.     if (Sys::stat(pathname, sb) >= 0) {
  197. hits++;
  198. fi->serial = master++;
  199. fi->sb = sb;
  200. return (true);
  201.     } else {
  202. flushed++;
  203. cache[h] = NULL;
  204. delete fi;
  205. return (false);
  206.     }
  207. }
  208. if (fi->serial < oldest->serial)
  209.     oldest = fi;
  210. h = (u_int)(h*h) % CACHESIZE;
  211. fi = cache[h];
  212.     }
  213.     /*
  214.      * Pathname not found in the cache.
  215.      */
  216.     if (Sys::stat(pathname, sb) < 0)
  217. return (false);
  218.     if (addToCache && pathname[0] != '.') {
  219. if (fi) {
  220.     fi = oldest;
  221.     displaced++;
  222. } else
  223.     fi = cache[h] = new FileCache;
  224. fi->name = pathname;
  225. fi->serial = master++;
  226. fi->sb = sb;
  227.     }
  228.     return (true);
  229. }
  230. void
  231. FileCache::flush(const char* pathname)
  232. {
  233.     u_int h = hash(pathname);
  234.     u_int maxprobes = 5;
  235.     FileCache* fi = cache[h];
  236.     while (fi && --maxprobes) {
  237. if (fi->name == pathname) {
  238.     flushed++;
  239.     cache[h] = NULL;
  240.     delete fi;
  241.     break;
  242. }
  243. h = (u_int)(h*h) % CACHESIZE;
  244. fi = cache[h];
  245.     }
  246. }