If this were made optional (i.e. add a param to afsd), I would have no
objection to it being added in. Personally, I'd like to see the cache
implementation be much more modular - to allow plugging in different
back-end storage mechanisms in different cases.

-- Nathan

-----Original Message-----
From: Derek Atkins
To: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]
Sent: 7/7/01 9:21 AM
Subject: [OpenAFS-devel] PATCH: break up cache into reasonable subdirs for
large cache sizes

Here is the patch for afsd that breaks up the cache into multiple
subdirs of a more reasonable size.  Using this patch I could create
a 3GB cache in under 3 minutes on a Linux ext2 FS.  I also added the
afsd parameter '-files_per_dir' which can set the log(2) size of the
subdirs.  The default is 11 (2048 files).

This patch is against the 1.0.4 release.

Enjoy.

-derek

--- src/afsd/afsd.c-orig        Mon Apr 23 03:29:03 2001
+++ src/afsd/afsd.c     Sat Jul  7 10:17:47 2001
@@ -48,6 +48,8 @@
   *               This option is now disabled.
   *    -logfile   Place where to put the logfile (default in
<cache>/etc/AFSLog.
   *    -waitclose make close calls always synchronous (slows em down,
tho)
+  *    -files_per_subdir [n]   2^n is the number of files per cache
subdir.
+  *                            11 is default (meaning 2048 files)
   *    -shutdown  Shutdown afs daemons
 
*-----------------------------------------------------------------------
----*/
 
@@ -188,7 +190,7 @@
 char fullpn_AFSLogFile[1024];          /*Full pathname of AFSLOGFILE*/
 char fullpn_CacheInfo[1024];           /*Full pathname of CACHEINFO*/
 char fullpn_VFile[1024];               /*Full pathname of data cache
files*/
-char *vFileNumber;                     /*Ptr to the number part of
above pathname*/
+char *vFilePtr;                                /*Ptr to the number part
of above pathname*/
 int sawCacheMountDir = 0;              /* from cmd line */
 int sawCacheBaseDir = 0;
 int sawCacheBlocks = 0;
@@ -202,6 +204,8 @@
 int createAndTrunc = O_CREAT | O_TRUNC; /*Create & truncate on open*/
 int ownerRWmode        = 0600;                 /*Read/write OK by
owner*/
 static int filesSet = 0;               /*True if number of files
explicitly set*/
+static int expFilesPerDir = 11;
+static int nFilesPerDir;               /* # files per cache dir (2048)
*/
 static int nDaemons = 2;               /* Number of background daemons
*/
 static int chunkSize = 0;               /* 2^chunkSize bytes per chunk
*/
 static int dCacheSize = 300;            /* # of dcache entries */
@@ -225,6 +229,7 @@
 #else
 #define AFSD_INO_T afs_uint32
 #endif
+char *cache_dir_list = NULL;           /* Array of cache subdirs */
 AFSD_INO_T *inode_for_V;               /* Array of inodes for desired
                                         * cache files */
 int missing_DCacheFile = 1;            /*Is the DCACHEFILE missing?*/
@@ -387,6 +392,7 @@
   *
   * Arguments:
   *    fname : Char ptr to the filename to parse.
+  *    max   : integer for the highest number to accept
   *
   * Returns:
   *    >= 0 iff the file is really a data cache file numbered from 0 to
cacheFiles-1, or
@@ -399,21 +405,23 @@
   *    None.
 
*-----------------------------------------------------------------------
----*/
 
-int GetVFileNumber(fname)
+static int doGetXFileNumber(fname, filechar, maxNum)
     char *fname;
+    char filechar;
+    int maxNum;
 {
     int        computedVNumber;    /*The computed file number we
return*/
     int        filenameLen;        /*Number of chars in filename*/
     int        currDigit;          /*Current digit being processed*/
 
     /*
-     * The filename must have at least two characters, the first of
which must be a ``V''
+     * The filename must have at least two characters, the first of
which must be a ``filechar''
      * and the second of which cannot be a zero unless the file is
exactly two chars long.
      */
     filenameLen = strlen(fname);
     if (filenameLen < 2)
        return(-1);
-    if (fname[0] != 'V')
+    if (fname[0] != filechar)
        return(-1);
     if ((filenameLen > 2) && (fname[1] == '0'))
        return(-1);
@@ -437,6 +445,21 @@
        return(-1);
 }
 
+int GetVFileNumber(fname, maxFile)
+    char *fname;
+    int maxFile;
+{
+    return doGetXFileNumber(fname, 'V', maxFile);
+}
+
+int GetDDirNumber(fname, maxDir)
+    char *fname;
+    int maxDir;
+{
+    return doGetXFileNumber(fname, 'D', maxDir);
+}
+
+
 
/*----------------------------------------------------------------------
-------
   * CreateCacheFile
   *
@@ -446,6 +469,8 @@
   *
   * Arguments:
   *    fname : Full pathname of file to create.
+  *    statp : A pointer to a stat buffer which, if NON-NULL, will be
+  *            filled by fstat()
   *
   * Returns:
   *    0   iff the file was created,
@@ -458,8 +483,38 @@
   *    As described.
 
*-----------------------------------------------------------------------
----*/
 
-int CreateCacheFile(fname)
+int CreateCacheSubDir (basename, dirNum)
+     char *basename;
+     int dirNum;
+{
+    static char rn[] = "CreateCacheSubDir"; /* Routine Name */
+    char dir[1024];
+    int ret;
+
+    /* Build the new cache subdirectory */
+    sprintf (dir, "%s/D%d", basename, dirNum);
+
+    if (afsd_verbose)
+       printf("%s: Creating cache subdir '%s'\n",
+              rn, dir);
+
+    if ((ret = mkdir(dir, 0700)) != 0) {
+        printf("%s: Can't create '%s', error return is %d (%d)\n",
+              rn, dir, ret, errno);
+        if (errno != EEXIST)
+           return (-1);
+    }
+
+    /* Mark this directory as created */
+    cache_dir_list[dirNum] = 1;
+
+    /* And return success */
+    return (0);
+}
+
+int CreateCacheFile(fname, statp)
     char *fname;
+    struct stat *statp;
 {
     static char        rn[] = "CreateCacheFile";   /*Routine name*/
     int        cfd;                                /*File descriptor to
AFS cache file*/
@@ -474,6 +529,14 @@
               rn, fname, cfd, errno);
        return(-1);
     }
+    if (statp != NULL) {
+        closeResult = fstat (cfd, statp);
+       if (closeResult) {
+           printf("%s: Can't stat newly-created AFS cache file '%s'
(code %d)\n",
+                  rn, fname, errno);
+           return(-1);
+       }
+    }
     closeResult = close(cfd);
     if (closeResult) {
        printf("%s: Can't close newly-created AFS cache file '%s' (code
%d)\n",
@@ -489,7 +552,7 @@
   *
   * Description:
   *    Sweep through the AFS cache directory, recording the inode
number for
-  *    each valid data cache file there.  Also, delete any file that
doesn't beint32
+  *    each valid data cache file there.  Also, delete any file that
doesn't belong
   *    in the cache directory during this sweep, and remember which of
the other
   *    residents of this directory were seen.  After the sweep, we
create any data
   *    cache files that were missing.
@@ -512,10 +575,15 @@
   *    explained above.
 
*-----------------------------------------------------------------------
----*/
 
-int SweepAFSCache(vFilesFound)
-    int *vFilesFound;
+
+static int doSweepAFSCache(vFilesFound,directory,dirNum,maxFile,maxDir)
+     int *vFilesFound;
+     char *directory;          /* /path/to/cache/directory */
+     int dirNum;               /* current directory number */
+     int maxFile;              /* maximum file number for this
directory */
+     int maxDir;               /* maximum directory number */
 {
-    static char        rn[] = "SweepAFSCache"; /*Routine name*/
+    static char rn[] = "doSweepAFSCache"; /* Routine Name */
     char fullpn_FileToDelete[1024];    /*File to be deleted from
cache*/
     char *fileToDelete;                        /*Ptr to last component
of above*/
     DIR        *cdirp;                         /*Ptr to cache directory
structure*/
@@ -525,36 +593,33 @@
     struct dirent *currp;              /*Current directory entry*/
 #endif
     int        vFileNum;                       /*Data cache file's
associated number*/
-
-    if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
-       if (afsd_debug)
-           printf("%s: Memory Cache, no cache sweep done\n", rn);
-       *vFilesFound = 0;
-       return 0;
-    }
+    int thisDir;
 
     if (afsd_debug)
-       printf("%s: Opening cache directory '%s'\n",
-              rn, cacheBaseDir);
+       printf("%s: Opening cache directory '%s'\n", rn, directory);
 
-    if (chmod(cacheBaseDir, 0700)) {           /* force it to be 700 */
-       printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n",
-              rn, cacheBaseDir);
+    if (chmod(directory, 0700)) {              /* force it to be 700 */
+       printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n", rn,
directory);
        return (-1);
     }
-    cdirp = opendir(cacheBaseDir);
+    cdirp = opendir(directory);
     if (cdirp == (DIR *)0) {
-       printf("%s: Can't open AFS cache directory, '%s'.\n",
-              rn, cacheBaseDir);
+       printf("%s: Can't open AFS cache directory, '%s'.\n", rn,
directory);
        return(-1);
     }
 
+    /* Precompute this directory number */
+    if (dirNum >= 0)
+      thisDir = dirNum <<  expFilesPerDir;
+
     /*
-     * Scan the directory entries, remembering data cache file inodes
and the existance
-     * of other important residents.  Delete all files that don't
belong here.
+     * Scan the directory entries, remembering data cache file inodes
+     * and the existance of other important residents.  Recurse into
+     * the data subdirectories.
+     *
+     * Delete all files and directories that don't belong here.
      */
-    *vFilesFound = 0;
-    sprintf(fullpn_FileToDelete, "%s/", cacheBaseDir);
+    sprintf(fullpn_FileToDelete, "%s/", directory);
     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
 
 #ifdef AFS_SGI62_ENV
@@ -576,24 +641,48 @@
        }
 
        /*
-        * Guess current entry is for a data cache file.
+        * If dirNum == -1, we are a top-level cache directory and
should
+        * only contain sub-directories and other sundry files.
Therefore,
+        * V-files are valid only if dirNum >= 0, and Directories are
only
+        * valid if dirNum == -1.
         */
-       vFileNum = GetVFileNumber(currp->d_name);
-       if (vFileNum >= 0) {
+
+       if (dirNum >= 0 && (*(currp->d_name) == 'V') &&
+           ((vFileNum = GetVFileNumber(currp->d_name, maxFile)) >= 0))
{
            /*
-            * Found a valid data cache filename.  Remember this file's
inode and bump
-            * the number of files found.
+            * Found a valid data cache filename.  Remember this
+            * file's inode and bump the number of files found.
             */
-           inode_for_V[vFileNum] = currp->d_ino;
+           inode_for_V[thisDir + vFileNum] = currp->d_ino;
            (*vFilesFound)++;
        }
-       else if (strcmp(currp->d_name, DCACHEFILE) == 0) {
+       else if (dirNum == -1 && (*(currp->d_name) == 'D') &&
+                ((vFileNum = GetDDirNumber(currp->d_name, maxDir)) >=
0)) {
+           int retval;
+           int mf = min (nFilesPerDir,
+                         (cacheFiles-(vFileNum << expFilesPerDir)));
+
+           /* Found a valid cachefile sub-Directory.  Remember this
number
+            * and recurse into it.  Note that subdirs cannot have
subdirs.
+            */
+           cache_dir_list[dirNum] = 1;
+
+           sprintf(fileToDelete, "%s", currp->d_name);
+           retval = doSweepAFSCache(vFilesFound, fullpn_FileToDelete,
+                                    vFileNum, mf, 0);
+           if (retval) {
+               printf ("%s: Recursive sweep failed on directory %s\n",
+                       rn, currp->d_name);
+               return retval;
+           }
+       }
+       else if (dirNum == -1 && strcmp(currp->d_name, DCACHEFILE) == 0)
{
            /*
             * Found the file holding the dcache entries.
             */
            missing_DCacheFile = 0;
        }
-       else if (strcmp(currp->d_name, VOLINFOFILE) == 0) {
+       else if (dirNum == -1 && strcmp(currp->d_name, VOLINFOFILE) ==
0) {
            /*
             * Found the file holding the volume info.
             */
@@ -614,55 +703,82 @@
        }
        else {
            /*
-            * This file doesn't belong in the cache.  Nuke it.
+            * This file/directory doesn't belong in the cache.  Nuke
it.
             */
            sprintf(fileToDelete, "%s", currp->d_name);
            if (afsd_verbose)
                printf("%s: Deleting '%s'\n",
                       rn, fullpn_FileToDelete);
            if (unlink(fullpn_FileToDelete)) {
-               printf("%s: Can't unlink '%s', errno is %d\n",
-                      rn, fullpn_FileToDelete, errno);
+               if (errno == EISDIR && *fileToDelete == 'D') {
+                   if (rmdir(fullpn_FileToDelete)) {
+                       printf("%s: Can't rmdir '%s', errno is %d\n",
+                              rn, fullpn_FileToDelete, errno);
+                   }
+               } else
+                   printf("%s: Can't unlink '%s', errno is %d\n",
+                          rn, fullpn_FileToDelete, errno);
            }
        }
     }
 
-    /*
-     * Create all the cache files that are missing.
-     */
-    if (missing_DCacheFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n",
-                  rn, fullpn_DCacheFile);
-       if (CreateCacheFile(fullpn_DCacheFile))
-           printf("%s: Can't create '%s'\n",
-                  rn, fullpn_DCacheFile);
-    }
-    if (missing_VolInfoFile) {
-       if (afsd_verbose)
-           printf("%s: Creating '%s'\n",
-                  rn, fullpn_VolInfoFile);
-       if (CreateCacheFile(fullpn_VolInfoFile))
-           printf("%s: Can't create '%s'\n",
-                  rn, fullpn_VolInfoFile);
-    }
+    if (dirNum == -1) {
 
-    if (*vFilesFound < cacheFiles) {
-       /*
-        * We came up short on the number of data cache files found.
Scan through the inode
-        * list and create all missing files.
+        /*
+        * Create all the cache files that are missing.
         */
-       for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++)
-           if (inode_for_V[vFileNum] == (AFSD_INO_T)0) {
-               sprintf(vFileNumber, "%d", vFileNum);
-               if (afsd_verbose)
-                   printf("%s: Creating '%s'\n",
-                          rn, fullpn_VFile);
-               if (CreateCacheFile(fullpn_VFile))
-                   printf("%s: Can't create '%s'\n",
-                          rn, fullpn_VFile);
-           }
-    }
+        if (missing_DCacheFile) {
+           if (afsd_verbose)
+               printf("%s: Creating '%s'\n",
+                      rn, fullpn_DCacheFile);
+           if (CreateCacheFile(fullpn_DCacheFile, NULL))
+               printf("%s: Can't create '%s'\n",
+                      rn, fullpn_DCacheFile);
+       }
+       if (missing_VolInfoFile) {
+           if (afsd_verbose)
+               printf("%s: Creating '%s'\n",
+                      rn, fullpn_VolInfoFile);
+           if (CreateCacheFile(fullpn_VolInfoFile, NULL))
+               printf("%s: Can't create '%s'\n",
+                      rn, fullpn_VolInfoFile);
+       }
+
+       if (*vFilesFound < cacheFiles) {
+           /*
+            * We came up short on the number of data cache files found.
+            * Scan through the inode list and create all missing files.
+            */
+           for (thisDir = 0; thisDir < maxDir; thisDir++) {
+               int maxFile = min (nFilesPerDir,
+                                  (cacheFiles-(thisDir <<
expFilesPerDir)));
+               int dnum = thisDir << expFilesPerDir;
+
+               for (vFileNum = 0; vFileNum < maxFile; vFileNum++) {
+                   int thisFile = dnum+vFileNum;
+
+                   if (inode_for_V[thisFile] == (AFSD_INO_T)0) {
+                       struct stat statb;
+
+                       sprintf(vFilePtr, "D%d/V%d", thisDir, vFileNum);
+                       if (afsd_verbose)
+                           printf("%s: Creating '%s'\n", rn,
fullpn_VFile);
+                       if (cache_dir_list[thisDir] == 0 &&
+                           CreateCacheSubDir(directory, thisDir))
+                           printf("%s: Can't create directory for
'%s'\n",
+                                  rn, fullpn_VFile);
+                       if (CreateCacheFile(fullpn_VFile, &statb))
+                           printf("%s: Can't create '%s'\n",
+                                  rn, fullpn_VFile);
+                       else {
+                           inode_for_V[thisFile] = statb.st_ino;
+                           *vFilesFound++;
+                       }
+                   }
+               } /* for (fileNum...) */
+           } /* for (thisDir...) */
+       } /* filesfound < cachefiles */
+    } /* dirNum == -1 */
     
     /*
      * Close the directory, return success.
@@ -674,6 +790,33 @@
     return(0);
 }
 
+int SweepAFSCache(vFilesFound)
+    int *vFilesFound;
+{
+    static char        rn[] = "SweepAFSCache"; /*Routine name*/
+    int maxDir = (cacheFiles >> expFilesPerDir) + 1;
+
+    *vFilesFound = 0;
+    nFilesPerDir = 1<<expFilesPerDir; /* pre-compute number of files */
+
+    if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
+       if (afsd_debug)
+           printf("%s: Memory Cache, no cache sweep done\n", rn);
+       return 0;
+    }
+
+    if (cache_dir_list == NULL) {
+        cache_dir_list = (char *) malloc (maxDir);
+       if (cache_dir_list == NULL) {
+           printf("%s: Malloc Failed!\n", rn);
+           return (-1);
+       }
+       memset (cache_dir_list, 0, maxDir);
+    }
+
+    return doSweepAFSCache (vFilesFound, cacheBaseDir, -1, 0, maxDir);
+}
+
 static ConfigCell(aci, arock, adir)
 register struct afsconf_cell *aci;
 char *arock;
@@ -896,6 +1039,14 @@
        /* -mem_alloc_sleep */
        cacheFlags |= AFSCALL_INIT_MEMCACHE_SLEEP;
     }
+    if (as->parms[24].items) {
+        /* -files_per_subdir */
+       expFilesPerDir = atoi(as->parms[24].items->data);
+       if (expFilesPerDir < 2 || expFilesPerDir > 30) {
+           printf("afsd:invalid cache subdir size spec'd, forcing one
subdir\n");
+           expFilesPerDir = 30;
+       }
+    }
 
     /*
      * Pull out all the configuration info for the workstation's AFS
cache and
@@ -925,7 +1076,7 @@
 
     if ((logfd = fopen(fullpn_AFSLogFile,"r+")) == 0) {
        if (afsd_verbose)  printf("%s: Creating '%s'\n",  rn,
fullpn_AFSLogFile);
-       if (CreateCacheFile(fullpn_AFSLogFile)) {
+       if (CreateCacheFile(fullpn_AFSLogFile, NULL)) {
            printf("%s: Can't create '%s' (You may want to use the
-logfile option)\n",  rn, fullpn_AFSLogFile);
            exit(1);
        }
@@ -1029,8 +1180,8 @@
      */
     sprintf(fullpn_DCacheFile,  "%s/%s", cacheBaseDir, DCACHEFILE);
     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
-    sprintf(fullpn_VFile,       "%s/V",  cacheBaseDir);
-    vFileNumber = fullpn_VFile + strlen(fullpn_VFile);
+    sprintf(fullpn_VFile,       "%s/",  cacheBaseDir);
+    vFilePtr = fullpn_VFile + strlen(fullpn_VFile);
 
 #if 0
     fputs(AFS_GOVERNMENT_MESSAGE, stdout); 
@@ -1460,6 +1611,7 @@
     cmd_AddParm(ts, "-enable_peer_stats", CMD_FLAG,
CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics by peer");
     cmd_AddParm(ts, "-enable_process_stats", CMD_FLAG,
CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics for this process");
     cmd_AddParm(ts, "-mem_alloc_sleep", CMD_FLAG, (CMD_OPTIONAL |
CMD_HIDE), "Allow sleeps when allocating memory cache");
+    cmd_AddParm(ts, "-files_per_subdir", CMD_SINGLE, CMD_OPTIONAL,
"log(2) of the number of cache files per cache subdirectory");
     return (cmd_Dispatch(argc, argv));
 }
 



-- 
       Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
       Member, MIT Student Information Processing Board  (SIPB)
       URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
       [EMAIL PROTECTED]                        PGP key available
_______________________________________________
OpenAFS-devel mailing list
[EMAIL PROTECTED]
https://lists.openafs.org/mailman/listinfo/openafs-devel
_______________________________________________
OpenAFS-devel mailing list
[EMAIL PROTECTED]
https://lists.openafs.org/mailman/listinfo/openafs-devel

Reply via email to