Greetings,

Some time ago there was a discussion on the list regarding the estimates
feature. Since then it has evolved into a "vos size" feature, and has, in
fact been implemented in some sense.

Attached is a patch that attempts to add the feature we needed most: the
size of the volume dump, however, the data structures are extensible, so
if there is need for other "measurements" such as number of files, number
of directories, whatever, these should be possible to add without too much
trouble.

In any case, here's the patch, and I'm patiently waiting for comments.

-Ilya
diff -u -r -x CVS openafs.orig/src/volser/dumpstuff.c openafs/src/volser/dumpstuff.c
--- openafs.orig/src/volser/dumpstuff.c Fri Mar 28 04:35:58 2003
+++ openafs/src/volser/dumpstuff.c      Mon May 19 17:36:17 2003
@@ -90,6 +90,17 @@
 static bit32 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t *handleP,
                              Error *status);
 
+static int SizeDumpDumpHeader(register struct iod *iodp, register Volume *vp,
+                             afs_int32 fromtime, register struct volintSize *size);
+static int SizeDumpPartial(register struct iod *iodp, register Volume *vp,
+                          afs_int32 fromtime, int dumpAllDirs,
+                          register struct volintSize *size);
+static int SizeDumpVnodeIndex(register struct iod *iodp, Volume *vp,
+                             VnodeClass class, afs_int32 fromtime, int forcedump,
+                             register struct volintSize *size);
+static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
+                        int volid, int vnodeNumber, int dumpEverything,
+                        register struct volintSize *size);
 
 static void iod_Init(register struct iod *iodp, register struct rx_call *call)
 {
@@ -1149,3 +1160,211 @@
     iod_ungetc(iodp, tag);
     return 1;
 }
+
+
+/* ----- Below are the calls that calculate dump size ----- */
+
+static int SizeDumpVolumeHeader(register struct iod *iodp, register Volume *vp, 
register struct volintSize *v_size)
+{
+    int code = 0;
+    static char nullString[1] = "";  /*The ``contents'' of motd*/
+
+/*     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER); */
+    v_size->dump_size += 1;
+/*     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));} */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
+    v_size->dump_size += (2 + strlen(V_name(vp)));
+/*     if (!code) code = DumpBool(iodp, 's',V_inService(vp)); */
+    v_size->dump_size += 2;
+/*     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp)); */
+    v_size->dump_size += 2;
+/*     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp)); */
+    v_size->dump_size += 2;
+/*     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));} */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));      /\* Rw volume 
creation date *\/ */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));                /\* Rw 
volume backup clone date *\/ */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp)); */
+    v_size->dump_size += (2 + strlen(V_offlineMessage(vp)));
+/*     /\* */
+/*      * We do NOT dump the detailed volume statistics residing in the old */
+/*      * motd field, since we cannot tell from the info in a dump whether */
+/*      * statistics data has been put there.  Instead, we dump a null string, */
+/*      * just as if that was what the motd contained. */
+/*      *\/ */
+/*     if (!code) code = DumpString(iodp, 'M', nullString); */
+    v_size->dump_size += (2 + strlen(nullString));
+/*     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), 
sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])); */
+    v_size->dump_size += (3 + 4*(sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])));
+/*     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
+    v_size->dump_size += 5;
+    return code;
+}
+
+static int SizeDumpEnd(register struct iod *iodp, register struct volintSize *v_size)
+{
+    int code = 0;
+    v_size->dump_size += 5;
+    return code;
+}
+
+int SizeDumpVolume(register struct rx_call *call, register Volume *vp, afs_int32 
fromtime,
+                  int dumpAllDirs, register struct volintSize *v_size)
+{
+    struct iod iod;
+    int code = 0;
+    register struct iod *iodp = (struct iod *)0;
+//    iod_Init(iodp, call);
+
+    if (!code) code = SizeDumpDumpHeader(iodp, vp, fromtime, v_size);
+    if (!code) code = SizeDumpPartial(iodp, vp, fromtime, dumpAllDirs, v_size);
+    if (!code) code = SizeDumpEnd(iodp, v_size);
+    
+    return code;
+}
+
+static int SizeDumpDumpHeader(register struct iod *iodp, register Volume *vp, 
afs_int32 fromtime,
+                             register struct volintSize *v_size)
+{
+    int code = 0;
+    int UseLatestReadOnlyClone = 1;
+    afs_int32 dumpTimes[2];
+//    iodp->device = vp->device;
+//    iodp->parentId = V_parentId(vp);
+//    iodp->dumpPartition = vp->partition;
+
+    v_size->dump_size = 0; /* initialize the size */
+/*     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION); 
*/
+    v_size->dump_size += 9;
+/*     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): 
V_parentId(vp)); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
+    v_size->dump_size += (2 + strlen(V_name(vp)));
+/*     dumpTimes[0] = fromtime; */
+/*     dumpTimes[1] = V_backupDate(vp);        /\* Until the time the clone was made 
*\/ */
+/*     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2); */
+    v_size->dump_size += (3 + 4*2);
+    return code;
+}
+
+static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int 
volid, int vnodeNumber, int dumpEverything,
+                    register struct volintSize *v_size)
+{
+    int code = 0;
+
+    if (!v || v->type == vNull)
+       return code;
+/*     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier); */
+    v_size->dump_size += 9;
+    if (!dumpEverything)
+        return code;
+/*     if (!code)  code = DumpByte(iodp, 't',(byte)v->type); */
+    v_size->dump_size += 2;
+/*     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /\* May not need this 
*\/ */
+    v_size->dump_size += 3;
+/*     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'a', v->author); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 'o', v->owner); */
+    v_size->dump_size += 5;
+/*     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);   /\* default 
group is 0 *\/ */
+    if(v->group)     v_size->dump_size += 5;
+/*     if (!code) code = DumpShort(iodp, 'b', v->modeBits); */
+    v_size->dump_size += 3;
+/*     if (!code) code = DumpInt32(iodp, 'p', v->parent); */
+    v_size->dump_size += 5;
+/*     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime); */
+    v_size->dump_size += 5;
+    if (v->type == vDirectory) {
+/*     acl_HtonACL(VVnodeDiskACL(v)); */
+/*     if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), 
VAclDiskSize(v)); */
+       v_size->dump_size += 1 + VAclDiskSize(v);
+    }
+
+    if (VNDISK_GET_INO(v)) {
+       v_size->dump_size += (v->length + 5);
+    } 
+    return code;
+}
+
+/* A partial dump (no dump header) */
+static int SizeDumpPartial(register struct iod *iodp, register Volume *vp, afs_int32 
fromtime, int dumpAllDirs,
+                          register struct volintSize *v_size)
+{
+    int code = 0;
+    if (!code) code = SizeDumpVolumeHeader(iodp, vp, v_size);
+    if (!code) code = SizeDumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs, 
v_size);
+    if (!code) code = SizeDumpVnodeIndex(iodp, vp, vSmall, fromtime, 0, v_size);
+    return code;
+}
+
+static int SizeDumpVnodeIndex(register struct iod *iodp, Volume *vp, VnodeClass 
class, afs_int32 fromtime,
+                             int forcedump, register struct volintSize *v_size)
+{
+    register int code = 0;
+    register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
+    char buf[SIZEOF_LARGEDISKVNODE];
+    struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
+    StreamHandle_t *file;
+    FdHandle_t *fdP;
+    int size;
+    int flag;
+    register int vnodeIndex, nVnodes;
+
+    fdP = IH_OPEN(vp->vnodeIndex[class].handle);
+    assert(fdP != NULL);
+    file = FDH_FDOPEN(fdP, "r+");
+    assert(file != NULL);
+    size = OS_SIZE(fdP->fd_fd);
+    assert(size != -1);
+   nVnodes = (size / vcp->diskSize) - 1;
+    if (nVnodes > 0) {
+       assert((nVnodes+1)*vcp->diskSize == size);
+       assert(STREAM_SEEK(file, vcp->diskSize, 0) == 0);
+    }
+    else nVnodes = 0;
+    for (vnodeIndex = 0; nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 
&& !code;
+      nVnodes--, vnodeIndex++) {
+       flag = forcedump || (vnode->serverModifyTime >= fromtime);
+       /* Note:  the >= test is very important since some old volumes may not have
+          a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
+          does dump the file! */
+       if (!code) code = SizeDumpVnode(iodp, vnode, V_id(vp), 
bitNumberToVnodeNumber(vnodeIndex, class), flag, v_size);
+    }
+    STREAM_CLOSE(file);
+    FDH_CLOSE(fdP);
+    return code;
+}
+
diff -u -r -x CVS openafs.orig/src/volser/volint.xg openafs/src/volser/volint.xg
--- openafs.orig/src/volser/volint.xg   Fri Mar 14 15:46:56 2003
+++ openafs/src/volser/volint.xg        Thu May 29 16:21:20 2003
@@ -48,6 +48,7 @@
 #define            VOLXLISTPARTITIONS  127
 #define            VOLFORWARDMULTIPLE  128
 #define     VOLCONVERTRO        65536
+#define     VOLGETSIZE          65537
 
 const SIZE = 1024;
 
@@ -216,6 +217,11 @@
        struct destServer server;
 };
 
+/*  Various size parameters of the volume  */
+struct volintSize {
+    afs_uint64 dump_size;
+};
+
 typedef  replica manyDests<>;
 typedef  afs_int32 manyResults<>;
 typedef  transDebugInfo transDebugEntries<>;
@@ -396,3 +402,9 @@
   IN afs_int32 partid,
   IN afs_int32 volid
 ) = VOLCONVERTRO;
+
+proc GetSize(
+  IN afs_int32 fromTrans,
+  IN afs_int32 fromDate,
+  OUT struct volintSize *size
+) = VOLGETSIZE;
diff -u -r -x CVS openafs.orig/src/volser/volprocs.c openafs/src/volser/volprocs.c
--- openafs.orig/src/volser/volprocs.c  Mon May 12 21:58:32 2003
+++ openafs/src/volser/volprocs.c       Mon May 19 17:40:47 2003
@@ -2797,6 +2797,33 @@
 #endif /* AFS_NAMEI_ENV */
 }
 
+afs_int32 SAFSVolGetSize (acid, fromTrans, fromDate, size)
+struct rx_call *acid;
+afs_int32 fromTrans;
+afs_int32 fromDate;
+register struct volintSize *size;
+{
+    int code = 0;
+    register struct volser_trans *tt;
+    char caller[MAXKTCNAMELEN];
+
+    if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;/*not a super 
user*/
+    tt = FindTrans(fromTrans);
+    if (!tt) return ENOENT;
+    if (tt->vflags & VTDeleted) {
+       TRELE(tt);
+       return ENOENT;
+    }
+    strcpy(tt->lastProcName,"GetSize"); 
+    tt->rxCallPtr = acid; 
+    code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size);        /* measure 
volume's data */
+    tt->rxCallPtr = (struct rx_call *)0; 
+    if(TRELE(tt)) return VOLSERTRELE_ERROR; 
+    
+/*    osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);  */
+    return code;
+}
+
 /* GetPartName - map partid (a decimal number) into pname (a string)
  * Since for NT we actually want to return the drive name, we map through the
  * partition struct.
diff -u -r -x CVS openafs.orig/src/volser/vos.c openafs/src/volser/vos.c
--- openafs.orig/src/volser/vos.c       Fri Mar 14 15:46:56 2003
+++ openafs/src/volser/vos.c    Wed May 28 13:17:30 2003
@@ -4300,6 +4300,80 @@
     return code;
 }
 
+static Sizes(as)
+register struct cmd_syndesc *as;
+{
+    afs_int32 avolid, aserver, apart,voltype,fromdate=0,code, err, i;
+    struct nvldbentry entry;
+    volintSize vol_size;
+    
+    rx_SetRxDeadTime(60 * 10);
+    for (i = 0; i<MAXSERVERS; i++) {
+       struct rx_connection *rxConn = ubik_GetRPCConn(cstruct,i);
+       if (rxConn == 0) break;
+       rx_SetConnDeadTime(rxConn, rx_connDeadTime);
+       if (rxConn->service)  rxConn->service->connDeadTime = rx_connDeadTime;
+    }
+    
+    avolid = vsu_GetVolumeID(as->parms[0].items->data, cstruct, &err);
+    if (avolid == 0) {
+       if (err) PrintError("", err);
+       else  fprintf(STDERR, "vos: can't find volume '%s'\n", 
as->parms[0].items->data);
+       return ENOENT;
+    }
+    
+    if (as->parms[1].items || as->parms[2].items) {
+       if (!as->parms[1].items || !as->parms[2].items) {
+           fprintf(STDERR, "Must specify both -server and -partition options\n");
+           return -1;
+       }
+       aserver = GetServer(as->parms[2].items->data);
+       if (aserver == 0) {
+           fprintf(STDERR, "Invalid server name\n");
+           return -1;
+       }
+       apart = volutil_GetPartitionID(as->parms[1].items->data);
+       if (apart < 0) {
+           fprintf(STDERR, "Invalid partition name\n");
+           return -1;
+       }
+    } else {
+       code = GetVolumeInfo(avolid, &aserver, &apart, &voltype, &entry);
+       if (code) return code;
+    }
+
+    fromdate = 0;
+    
+    if (as->parms[4].items && strcmp(as->parms[4].items->data,"0")) {
+       code = ktime_DateToInt32(as->parms[4].items->data, &fromdate);
+       if (code) {
+           fprintf(STDERR,"vos: failed to parse date '%s' (error=%d))\n",
+                   as->parms[1].items->data, code);
+           return code;
+       }
+    }
+
+    fprintf(STDOUT, "Volume: %s\n", as->parms[0].items->data);
+    
+    if(as->parms[3].items) /* do the dump estimate */
+    {
+       vol_size.dump_size = 0;
+       code = UV_GetSize(avolid, aserver, apart, fromdate, &vol_size);
+       if (code) {
+           PrintDiagnostics("size", code);
+           return code;
+       }
+       /* presumably the size info is now gathered in pntr */
+       /* now we display it */
+       
+       fprintf(STDOUT,"dump_size: %llu\n", vol_size.dump_size);
+    }
+    
+    /* Display info */
+    
+    return 0;
+}
+
 PrintDiagnostics(astring, acode)
     char *astring;
     afs_int32 acode;
@@ -4608,6 +4682,14 @@
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL, "don't ask");
     COMMONPARMS;
 
+    ts = cmd_CreateSyntax("size", Sizes, 0, "obtain various sizes of the volume.");
+    cmd_AddParm(ts, "-id", CMD_SINGLE, 0, "volume name or ID");
+    cmd_AddParm(ts, "-partition", CMD_SINGLE, CMD_OPTIONAL, "partition name");
+    cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_OPTIONAL,  "machine name");
+    cmd_AddParm(ts, "-dump", CMD_FLAG, CMD_OPTIONAL, "Obtain the size of the dump");
+    cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
+    COMMONPARMS;
+
     code = cmd_Dispatch(argc, argv);
     if (rxInitDone) {
        /* Shut down the ubik_client and rx connections */
diff -u -r -x CVS openafs.orig/src/volser/vsprocs.c openafs/src/volser/vsprocs.c
--- openafs.orig/src/volser/vsprocs.c   Fri Mar 28 04:27:32 2003
+++ openafs/src/volser/vsprocs.c        Mon May 19 17:41:10 2003
@@ -3026,6 +3026,8 @@
    EGOTO(error_exit, code, "Error while dumping volume \n");
    VDONE;
 
+   VPRINT1("tid: %d\n", fromtid);
+   
  error_exit: 
    if (fromcall) {
       code = rx_EndCall(fromcall, rxError);
@@ -5568,6 +5570,45 @@
   return(error);
 }
 
+int UV_GetSize(afs_int32 afromvol, afs_int32 afromserver, afs_int32 afrompart, 
+       afs_int32 fromdate, struct volintSize *vol_size)
+{
+   struct rx_connection *aconn = (struct rx_connection *)0;
+   afs_int32 tid=0, rcode=0;
+   afs_int32 code, error = 0;
+
+
+   /* get connections to the servers */
+   aconn = UV_Bind(afromserver, AFSCONF_VOLUMEPORT);
+
+   VPRINT1("Starting transaction on volume %u...", afromvol);
+   code = AFSVolTransCreate(aconn, afromvol, afrompart, ITBusy, &tid);
+   EGOTO1(error_exit, code, "Could not start transaction on the volume %u to be 
measured\n", afromvol);
+   VDONE;
+
+   VPRINT1("Getting size of volume on volume %u...", afromvol);
+   code = AFSVolGetSize(aconn, tid, fromdate, vol_size);
+   EGOTO(error_exit, code, "Could not start the measurement process \n");
+   VDONE;
+      
+ error_exit:
+   if (tid) {
+      VPRINT1("Ending transaction on volume %u...", afromvol);
+      code = AFSVolEndTrans(aconn, tid, &rcode);
+      if (code || rcode) {
+        fprintf(STDERR,"Could not end transaction on the volume %u\n", afromvol);
+        fprintf(STDERR,"error codes: %d and %d\n", code, rcode);
+        if (!error) error = (code?code:rcode);
+      }
+      VDONE;
+   }
+   if (aconn)
+      rx_DestroyConnection(aconn);
+
+   PrintError("", error);
+   return(error);
+}
+
 /*maps the host addresses in <old > (present in network byte order) to
  that in< new> (present in host byte order )*/
 void MapNetworkToHost(struct nvldbentry *old, struct nvldbentry *new)

Reply via email to