xdasd_mcache.c

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------------
00002  * Copyright (c) 2006, Novell, Inc.
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without 
00006  * modification, are permitted provided that the following conditions are 
00007  * met:
00008  * 
00009  *     * Redistributions of source code must retain the above copyright 
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright 
00012  *       notice, this list of conditions and the following disclaimer in the 
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Novell nor the names of its contributors 
00015  *       may be used to endorse or promote products derived from this 
00016  *       software without specific prior written permission.
00017  * 
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00019  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00020  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00021  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
00022  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00024  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
00025  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
00026  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
00027  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *--------------------------------------------------------------------------*/
00030 
00117 #include "xdasd_mcache.h"
00118 #include "xdasd_parse.h"
00119 #include "xdasd_log.h"
00120 
00121 #include "xdas_base.h"
00122 #include "xdas_wire.h"
00123 
00124 #ifdef _WIN32
00125 
00126 # define WIN32_LEAN_AND_MEAN
00127 # include <windows.h>
00128 # include <direct.h>
00129 # include <io.h>
00130 # include <fcntl.h>
00131 # include <sys/types.h>
00132 # include <sys/stat.h>
00133 # define mkdir(x,y)        _mkdir(x)
00134 # define open              _open
00135 # define lseek             _lseek
00136 # define read              _read
00137 # define write             _write
00138 # define close             _close
00139 # define unlink            _unlink
00140 # define MC_FILE_ATTRS     (_S_IREAD | _S_IWRITE)
00141 # define MC_OPEN_FLAGS     (_O_RDWR | _O_BINARY)
00142 # define MC_CREATE_FLAGS   (_O_RDWR | _O_CREAT | _O_BINARY)
00143 
00144 #else /* UNIX */
00145 
00146 # ifdef HAVE_CONFIG_H
00147 #  include "config.h"
00148 # endif
00149 # include <unistd.h>
00150 # include <sys/types.h>
00151 # include <sys/stat.h>
00152 # include <fcntl.h>
00153 # include <dirent.h>
00154 # if HAVE_INTTYPES_H
00155 #  include <inttypes.h>
00156 # else
00157 #  if HAVE_STDINT_H
00158 #   include <stdint.h>
00159 #  endif
00160 # endif
00161 # define MC_FILE_ATTRS     (0644)
00162 # define MC_DIR_ATTRS      (0744)
00163 # define MC_OPEN_FLAGS     (O_RDWR)
00164 # define MC_CREATE_FLAGS   (O_RDWR | O_CREAT)
00165 #endif
00166 
00167 #include <stddef.h>
00168 #include <stdio.h>
00169 #include <stdlib.h>
00170 #include <string.h>
00171 #include <malloc.h>
00172 
00177 /* The maximum size of a single message cache file (1 Mb). 
00178    The test versions are smaller so we don't have to write so 
00179    much to test file overflow, etc. 
00180  */
00181 #ifdef XDASD_MCACHE_TEST
00182 # define MCACHE_MAX_FILESZ  (1024 + 512)
00183 # define MCACHE_MAX_RECSZ   (512 + 256)
00184 #else
00185 # define MCACHE_MAX_FILESZ  (1024 * 1024)
00186 # define MCACHE_MAX_RECSZ   (64 * 1024)
00187 #endif
00188 
00190 #define MCACHE_BASE_FNAME  "xdasd.cache"
00191 
00192 /* The mcache file header array index values. */
00193 #define MCH_BOF   0
00194 #define MCH_EOF   1
00195 #define MCH_LIM   2
00196 
00198 typedef struct mcfile_
00199 {
00200    int fh;                    
00201    unsigned usecnt;           
00202    unsigned fileno;           
00203    uint32_t header[3];        
00204    char fname[FILENAME_MAX];  
00205 } mcfile_t;
00206 
00208 typedef struct mcache_
00209 {
00210    unsigned lofno;            
00211    unsigned hifno;            
00212    mcfile_t * ifp;            
00213    mcfile_t * ofp;            
00214    char mcdir[FILENAME_MAX];  
00215 } mcache_t;
00216 
00217 #ifdef _WIN32
00218 
00219 /* An implementation of opendir/readdir for Win32 */
00220 
00221 #define dirent _finddata_t
00222 #define d_name name
00223 
00225 typedef struct DIR_tag
00226 {
00227    intptr_t handle;
00228    struct _finddata_t fileinfo;
00229    char filespec[FILENAME_MAX];
00230 } DIR;
00231 
00240 static DIR * opendir(const char * name)
00241 {
00242    DIR * dir;
00243    size_t dirlen;
00244    if ((dir = (DIR *)malloc(sizeof(*dir))) == 0)
00245       return 0;
00246    memset(dir, 0, sizeof(*dir));
00247    dir->handle = -1;
00248    strncpy(dir->filespec, name, sizeof(dir->filespec));
00249    dir->filespec[sizeof(dir->filespec) - 1] = 0;
00250    dirlen = strlen(dir->filespec);
00251    if (dirlen > 0 && (dir->filespec[dirlen - 1] == '\\' 
00252          || dir->filespec[dirlen - 1] == '/'))
00253       dir->filespec[--dirlen] = 0;
00254    strcpy(dir->filespec + dirlen, "\\*");
00255    return dir;
00256 }
00257 
00266 static struct dirent * readdir(DIR * dir)
00267 {
00268    if ((dir->handle == -1 && (dir->handle = 
00269             _findfirst(dir->filespec, &dir->fileinfo)) == -1)
00270          || _findnext(dir->handle, &dir->fileinfo) != 0)
00271       return 0;
00272    return &dir->fileinfo;
00273 }
00274 
00283 static int closedir(DIR * dir)
00284 {
00285    int rc = _findclose(dir->handle);
00286    free(dir);
00287    return rc;
00288 }
00289 
00290 #endif
00291 
00315 static void mcache_calc_file_range(const char * mcdir, 
00316       unsigned * lowp, unsigned * highp)
00317 {
00318    DIR * dp;
00319    unsigned low = (unsigned)(-1);
00320    unsigned high = 0;
00321 
00322    /* attempt to open message cache file directory */
00323    if ((dp = opendir(mcdir)) != 0)
00324    {
00325       struct dirent * de;
00326 
00327       /* read each entry, scan for high and low file numbers */
00328       while ((de = readdir(dp)) != 0)
00329       {
00330          size_t namelen = strlen(de->d_name);
00331          if (namelen > 12 && strncmp("xdasd.cache.", de->d_name, 12) == 0)
00332          {
00333             unsigned fcval = atoi(de->d_name + 12);
00334             if (fcval != 0)   /* skip anything wierd... */
00335             {
00336                if (fcval < low)
00337                   low = fcval;
00338                if (fcval > high)
00339                   high = fcval;
00340             }
00341          }
00342       }
00343       closedir(dp);
00344    }
00345 
00346    /* return low and high values, or defaults (1), if not found. */
00347    *lowp = low < (unsigned)(-1)? low: 1;
00348    *highp = high > 0? high: 1;
00349 }
00350 
00364 static void mcache_close(mcfile_t * fp, int ferase)
00365 {
00366    if (fp != 0 && --fp->usecnt == 0)
00367    {
00368       close(fp->fh);
00369       if (ferase) 
00370          unlink(fp->fname);
00371       free(fp);
00372    }
00373 }
00374 
00388 static mcfile_t * mcache_dup(mcfile_t * fp)
00389 {
00390    if (fp)
00391       fp->usecnt++;
00392    return fp;
00393 }
00394 
00403 static int mcache_read_file_header(mcfile_t * fp)
00404 {
00405    char header[sizeof(fp->header)];
00406    char * cp = header;
00407 
00408    if (read(fp->fh, header, sizeof(header)) != sizeof(header))
00409       return -1;
00410 
00411    fp->header[MCH_BOF] = xdas_get_uint32(&cp);
00412    fp->header[MCH_EOF] = xdas_get_uint32(&cp);
00413    fp->header[MCH_LIM] = xdas_get_uint32(&cp);
00414 
00415    if (fp->header[MCH_LIM] > MCACHE_MAX_FILESZ
00416          || fp->header[MCH_EOF] > fp->header[MCH_LIM]
00417          || fp->header[MCH_BOF] > fp->header[MCH_EOF])
00418       return -1;
00419 
00420    return 0;
00421 }
00422 
00431 static int mcache_write_file_header(mcfile_t * fp)
00432 {
00433    char header[sizeof(fp->header)];
00434    char * cp = header;
00435 
00436    xdas_put_uint32(&cp, fp->header[MCH_BOF]);
00437    xdas_put_uint32(&cp, fp->header[MCH_EOF]);
00438    xdas_put_uint32(&cp, fp->header[MCH_LIM]);
00439 
00440    if (lseek(fp->fh, 0, SEEK_SET) == (off_t)(-1)
00441          || write(fp->fh, header, sizeof(header)) != sizeof(header))
00442       return -1;
00443 
00444    return 0;
00445 }
00446 
00457 static int mcache_open(const char * mcdir, unsigned fileno, mcfile_t ** fpp)
00458 {
00459    mcfile_t * fp;
00460 
00461    /* allocate and populate a new mcfile object */
00462    if ((fp = (mcfile_t *)malloc(sizeof(*fp))) == 0)
00463       return -1;
00464    memset(fp, 0, sizeof(*fp));
00465    fp->usecnt++;
00466    fp->fileno = fileno;
00467 
00468    /* build the file name, open file */
00469    sprintf(fp->fname, "%s/" MCACHE_BASE_FNAME ".%d", mcdir, fileno);
00470    if ((fp->fh = open(fp->fname, MC_OPEN_FLAGS)) < 0)
00471    {
00472       free(fp);
00473       return -1;
00474    }
00475 
00476    /* read header and do some sanity checks */
00477    if (mcache_read_file_header(fp) < 0)
00478    {
00479       mcache_close(fp, 0); /* close and erase the file */
00480       return -1;
00481    }
00482    *fpp = fp;
00483    return 0;
00484 }
00485 
00496 static int mcache_create(const char * mcdir, unsigned fileno, mcfile_t ** fpp)
00497 {
00498    mcfile_t * fp;
00499    
00500    mkdir(mcdir, MC_DIR_ATTRS);  /* ensure cache directory exists */  
00501 
00502    /* allocate and populate a new mcfile object */
00503    if ((fp = (mcfile_t *)malloc(sizeof(*fp))) == 0)
00504       return -1;
00505    memset(fp, 0, sizeof(*fp));
00506    fp->usecnt++;
00507    fp->fileno = fileno;
00508 
00509    /* build the file name, create file and fill in and write file header */
00510    sprintf(fp->fname, "%s/" MCACHE_BASE_FNAME ".%d", mcdir, fileno);
00511    if ((fp->fh = open(fp->fname, MC_CREATE_FLAGS, MC_FILE_ATTRS)) < 0)
00512    {
00513       free(fp);
00514       return -1;
00515    }
00516 
00517    fp->header[MCH_BOF] = sizeof(fp->header);
00518    fp->header[MCH_EOF] = sizeof(fp->header);
00519    fp->header[MCH_LIM] = MCACHE_MAX_FILESZ;
00520    if (mcache_write_file_header(fp) < 0)
00521    {
00522       mcache_close(fp, 1); /* close and erase the file */
00523       return -1;
00524    }
00525 
00526    /* flush */
00527 
00528    *fpp = fp;     /* return mcfile object pointer */
00529    return 0;
00530 }
00531 
00542 static int mcache_write_record(mcfile_t * fp, Parsed * parsed, size_t msgsz)
00543 {
00544    char buf[2 * sizeof(uint32_t) + (XDAS_FIELD_COUNT + 1) * sizeof(uint16_t)];
00545    char * cp = buf;
00546    int i;
00547 
00548    /* Actual message size is record size minus overhead:
00549          uint32_t recsz (size of remaining fields)
00550          uint32_t flags
00551          uint16_t offsets[XDAS_FIELD_COUNT + 1]
00552          char msg[msgsz] 
00553     */
00554    xdas_put_uint32(&cp, sizeof(buf) - sizeof(uint32_t) + msgsz);
00555    xdas_put_uint32(&cp, parsed->flags & PMF_IMPORTED);
00556    for (i = 0; i < XDAS_FIELD_COUNT + 1; i++)
00557       xdas_put_uint16(&cp, (uint16_t)(parsed->parsed[i] - parsed->msg));
00558 
00559    /* seek and write the entire record to the current end of file */
00560    if (lseek(fp->fh, fp->header[MCH_EOF], SEEK_SET) == (off_t)(-1)
00561          || write(fp->fh, buf, sizeof(buf)) != sizeof(buf)
00562          || write(fp->fh, parsed->msg, (unsigned)msgsz) != (int)msgsz)
00563       return -1;
00564 
00565    /* update the end of file and write the new file header */
00566    fp->header[MCH_EOF] += (uint32_t)(sizeof(buf) + msgsz);
00567    if (mcache_write_file_header(fp) < 0)
00568       return -1;
00569 
00570    /* flush */
00571 
00572    return 0;
00573 }
00574 
00591 static Parsed * mcache_read_record(mcfile_t * fp)
00592 {
00593    size_t recsz;
00594    uint32_t u32recsz;
00595    Parsed * parsed = 0;
00596 
00597    if (lseek(fp->fh, fp->header[MCH_BOF], SEEK_SET) != (off_t)(-1)
00598          && read(fp->fh, &u32recsz, sizeof(u32recsz)) == sizeof(u32recsz)
00599          && (recsz = AS_UINT32(&u32recsz)) < MCACHE_MAX_RECSZ)
00600    {
00601       char buf[sizeof(uint32_t) + (XDAS_FIELD_COUNT + 1) * sizeof(uint16_t)];
00602       size_t msgsz = recsz - sizeof(buf);
00603       size_t allocsz = offsetof(Parsed, msg) + msgsz;
00604       char * cp = buf;
00605       int i;
00606 
00607       /* Actual message size is record size minus overhead:
00608             uint32_t recsz (size of remaining fields)
00609             uint32_t flags
00610             uint16_t offsets[XDAS_FIELD_COUNT + 1]
00611             char msg[msgsz] 
00612        */
00613       if ((parsed = (Parsed *)malloc(allocsz)) == 0
00614             || read(fp->fh, buf, sizeof(buf)) != sizeof(buf)
00615             || read(fp->fh, parsed->msg, (unsigned)msgsz) != (int)msgsz)
00616       {
00617          free(parsed);
00618          return 0;
00619       }
00620 
00621       /* extract overhead and parse offsets - convert offsets to pointers */
00622       memset(parsed, 0, offsetof(Parsed, parsed));
00623       parsed->structsz = allocsz;
00624       parsed->flags = xdas_get_uint32(&cp);
00625       for (i = 0; i < XDAS_FIELD_COUNT + 1; i++)
00626       {
00627          parsed->parsed[i] = parsed->msg + xdas_get_uint16(&cp);
00628          if (parsed->parsed[i] < parsed->msg
00629                || parsed->parsed[i] > parsed->msg + msgsz)
00630          {
00631             free(parsed);
00632             return 0;
00633          }
00634       }
00635    }
00636    return parsed;
00637 }
00638 
00647 static int mcache_update_bof(mcfile_t * fp)
00648 {
00649    uint32_t u32msgsz;
00650 
00651    /* read message size at current BOF position */
00652    if (fp->header[MCH_BOF] >= fp->header[MCH_EOF]
00653          || lseek(fp->fh, fp->header[MCH_BOF], SEEK_SET) == (off_t)(-1)
00654          || read(fp->fh, &u32msgsz, sizeof(u32msgsz)) != sizeof(u32msgsz))
00655       return -1;
00656    
00657    /* move BOF ahead one message, write new header */
00658    fp->header[MCH_BOF] += sizeof(u32msgsz) + AS_UINT32(&u32msgsz);
00659    if (mcache_write_file_header(fp) < 0)
00660       return -1;
00661 
00662    /* flush */
00663 
00664    return 0;
00665 }
00666 
00679 static int mcache_put_msg(mcache_t * mcp, Parsed * parsed)
00680 {
00681    unsigned nextfno = mcp->hifno;
00682    size_t msgsz = parsed->parsed[XDAS_FIELD_COUNT] - parsed->parsed[0];
00683    size_t recsz = 2 * sizeof(uint32_t) 
00684          + (XDAS_FIELD_COUNT + 1) * sizeof(uint16_t) + msgsz;
00685 
00686    /* Actual record is:
00687          uint32_t recsz (size of remaining fields)
00688          uint32_t flags
00689          uint16_t offsets[XDAS_FIELD_COUNT + 1]
00690          char msg[msgsz] 
00691     */
00692    do
00693    {
00694       if (mcp->ifp != 0)
00695       {
00696          /* if this message is too big for current infile, close it */
00697          if (mcp->ifp->header[MCH_EOF] + recsz > mcp->ifp->header[MCH_LIM])
00698          {
00699             nextfno = mcp->ifp->fileno + 1;
00700             mcache_close(mcp->ifp, 0);       /* don't erase it */
00701             mcp->ifp = 0;
00702          }
00703       }
00704 
00705       /* open the next file, if there's not one open right now. */
00706       if (mcp->ifp == 0)
00707       {
00708          if (mcp->ofp && nextfno == mcp->ofp->fileno)
00709             mcp->ifp = mcache_dup(mcp->ofp);
00710          else if (mcache_open(mcp->mcdir, nextfno, &mcp->ifp) < 0
00711                && mcache_create(mcp->mcdir, nextfno, &mcp->ifp) < 0)
00712          {
00713             xdasd_log(0, "MCACHE: Unable to open message cache for write.\n");
00714             return -1;
00715          }
00716       }
00717    } while (mcp->ifp->header[MCH_EOF] + recsz > mcp->ifp->header[MCH_LIM]);
00718 
00719    /* write message to cache */
00720    if (mcache_write_record(mcp->ifp, parsed, msgsz) < 0)
00721    {
00722       xdasd_log(0, "MCACHE: Unable to write to message cache.\n");
00723       return -1;
00724    }
00725    return 0;
00726 }
00727 
00744 static Parsed * mcache_get_msg(mcache_t * mcp)
00745 {
00746    unsigned nextfno = mcp->lofno;   /* init to lowest file number */
00747 
00748    /* if outfile is already open, move BOF pointer ahead one message */
00749    if (mcp->ofp != 0)
00750    {
00751       /* move to next message in current file */
00752       if (mcache_update_bof(mcp->ofp) < 0)
00753          return 0;
00754 
00755       /* if at end of file, close and erase this file */
00756       if (mcp->ofp->header[MCH_BOF] >= mcp->ofp->header[MCH_EOF])
00757       {
00758          /* if cache is empty, then close input file too -
00759             the next put_msg will reopen the starting input file */
00760          if (mcp->ifp != 0 && mcp->ofp->fileno == mcp->ifp->fileno)
00761          {
00762             mcp->lofno = mcp->hifno = 1;
00763             mcache_close(mcp->ifp, 0);
00764             mcp->ifp = 0;
00765          }
00766 
00767          /* close output file */
00768          nextfno = mcp->ofp->fileno + 1;
00769          mcache_close(mcp->ofp, 1);
00770          mcp->ofp = 0;
00771       }
00772    }
00773 
00774    /* if file is closed, open the next one if there is one */
00775    if (mcp->ofp == 0)
00776    {
00777       /* attempt to dup/open the next message file */
00778       if (mcp->ifp && nextfno == mcp->ifp->fileno)
00779          mcp->ofp = mcache_dup(mcp->ifp);
00780       else if (mcache_open(mcp->mcdir, nextfno, &mcp->ofp) < 0)
00781          return 0;
00782    }
00783 
00784    /* read and return the current parsed message */
00785    return mcache_read_record(mcp->ofp);
00786 }
00787 
00791 /*--------------------------------------------------------------------------*/
00792 
00802 int xdasd_mcache_put_msg(MsgCache mc, Parsed * parsed)
00803 {
00804    return mcache_put_msg((mcache_t *)mc, parsed);
00805 }
00806 
00818 Parsed * xdasd_mcache_get_msg(MsgCache mc)
00819 {
00820    return mcache_get_msg((mcache_t *)mc);
00821 }
00822 
00835 MsgCache xdasd_mcache_create(const char * msgfdir)
00836 {
00837    mcache_t * mcp;
00838 
00839    if ((mcp = (mcache_t *)malloc(sizeof(*mcp))) == 0)
00840        return 0;
00841 
00842    /* store msg file directory name, zero file object pointers */
00843    strncpy(mcp->mcdir, msgfdir, sizeof(mcp->mcdir));
00844    mcp->mcdir[sizeof(mcp->mcdir) - 1] = 0;
00845    mcp->ifp = mcp->ofp = 0;
00846 
00847    /* calculate the startup file range found in the mcache directory */
00848    mcache_calc_file_range(mcp->mcdir, &mcp->lofno, &mcp->hifno);
00849 
00850    return (MsgCache)mcp;
00851 }
00852 
00859 void xdasd_mcache_destroy(MsgCache mc)
00860 {
00861    mcache_t * mcp = (mcache_t *)mc;
00862 
00863    /* close all cache files */
00864    mcache_close(mcp->ifp, 0);
00865    mcache_close(mcp->ofp, 0);
00866    free(mcp);
00867 }
00868 
00869 /*==========================================================================*/
00870 
00871 #ifdef XDASD_MCACHE_TEST
00872 
00873 #include <stdio.h>
00874 #include <stdlib.h>
00875 #include <stdarg.h>
00876 
00883 void xdasd_log(int level, const char * fmt, ... ) 
00884 {
00885 #ifdef LOG_TO_STDOUT
00886    va_list args;
00887    va_start(args, fmt);
00888    vprintf(fmt, args);
00889    va_end(args);
00890 #else
00891    (void)fmt;
00892 #endif
00893 }
00894 
00901 int xdasd_log_level(void) { return 0; }
00902 
00923 int main(int argc, char ** argv)
00924 {
00925 
00926 #define TESTMSG1 \
00927    "HDR:00A8:OX1:1CB1B348:::time.nist.gov:MST7MDT:0x10000001:0:ORG:" \
00928    "originator_location_name:originator_location_address:" \
00929    "originator_service_type:originator_authentication_authority:" \
00930    "originator_principal_name:originator_principal_id:" \
00931    "INT:initiator_auth_authority:initiator_domain_name:initiator_domain_id:" \
00932    "TGT:target_location_name:target_location_address:target_service_type:" \
00933    "target_auth_authority:target_principal_name:target_principal_id:" \
00934    "SRC:pointer_to_source_domain:EVT:event_specific_info:END"
00935 
00936 #define TESTMSG2 \
00937    "HDR:00B8:OX1:1FB7AC54:::time.ms.com:MST5MDT:0x10000002:0:ORG:" \
00938    "org_location_name:org_location_address:org_service_type:" \
00939    "org_auth_authority:org_principal_name:org_principal_id:INT:" \
00940    "int_auth_authority:int_domain_specific_name:int_domain_specific_id:" \
00941    "TGT:tgt_location_name:tgt_location_address:tgt_service_type:" \
00942    "tgt_auth_authority:tgt_principal_name:tgt_principal_id:" \
00943    "SRC:pointer_to_source_domain:EVT:event_specific_information:END"
00944 
00945    static struct 
00946    {
00947       char * msg;
00948       size_t msgsz;
00949    } msgs[] = 
00950    {
00951       {TESTMSG1, sizeof(TESTMSG1) - 1},
00952       {TESTMSG2, sizeof(TESTMSG2) - 1},
00953       {TESTMSG2, sizeof(TESTMSG2) - 1},
00954       {TESTMSG1, sizeof(TESTMSG1) - 1},
00955       {TESTMSG2, sizeof(TESTMSG2) - 1},
00956       {TESTMSG1, sizeof(TESTMSG1) - 1},
00957       {TESTMSG1, sizeof(TESTMSG1) - 1},
00958    };
00959 
00960    int i, j;
00961    DIR * dir;
00962    MsgCache mc;
00963    Parsed * parsed;
00964    struct dirent * de;
00965    char * cache_path = argc > 1? argv[1]: ".";
00966 
00967    /* start clean by removing all cache files from the cache directory */
00968    if ((dir = opendir(cache_path)) != 0)
00969    {
00970       while ((de = readdir(dir)) != 0)
00971          if (strncmp(de->d_name, MCACHE_BASE_FNAME, 
00972                sizeof(MCACHE_BASE_FNAME) - 1) == 0)
00973          {
00974             char fpath[FILENAME_MAX];
00975             sprintf(fpath, "%s\\%s", cache_path, de->d_name);
00976             unlink(fpath);
00977          }
00978       closedir(dir);
00979    }
00980 
00981    /* initialize the cache */
00982    mc = xdasd_mcache_create(cache_path);
00983 
00984    /* write half of the messages out to the cache */
00985    for (i = 0; i < (sizeof(msgs)/sizeof(*msgs)) / 2; i++)
00986    {
00987       int err;
00988 
00989       if ((err = xdasd_parse_message(PMF_IMPORTED, 
00990             msgs[i].msgsz, msgs[i].msg, &parsed)) != 0)
00991       {
00992          xdasd_log(0, "%s: error %d at: %s(%d), loop %d.\n", 
00993                argv[0], err, __FILE__, __LINE__, i);
00994          exit(1);
00995       }
00996       if ((err = xdasd_mcache_put_msg(mc, parsed)) != 0)
00997       {
00998          xdasd_log(0, "%s: error %d at: %s(%d), loop %d.\n", 
00999                argv[0], err, __FILE__, __LINE__, i);
01000          exit(1);
01001       }
01002       xdasd_parse_free(parsed);
01003    }
01004 
01005    /* simulate a crash */
01006    xdasd_mcache_destroy(mc);
01007 
01008    /* simulate restart with data in the cache */
01009    mc = xdasd_mcache_create(cache_path);
01010 
01011    /* retrieve two messages to see if they come out right */
01012    for (j = 0; j < 2; j++)
01013    {
01014       parsed = xdasd_mcache_get_msg(mc);
01015       if (parsed == 0 || parsed->parsed[XDAS_FIELD_COUNT] 
01016                - parsed->parsed[0] - 1 != (int)msgs[j].msgsz
01017             || strncmp(parsed->msg, msgs[j].msg, msgs[j].msgsz) != 0)
01018       {
01019          xdasd_log(0, "%s: corrupt cache detected at %s(%d), loop %d.\n", 
01020                argv[0], __FILE__, __LINE__, j);
01021          exit(1);                                  \
01022       }
01023       xdasd_parse_free(parsed);
01024    }
01025 
01026    /* simulate a crash */
01027    xdasd_mcache_destroy(mc);
01028 
01029    /* simulate restart with data in the cache */
01030    mc = xdasd_mcache_create(cache_path);
01031 
01032    /* write remaining elements to the cache */
01033    for ( ; i < sizeof(msgs)/sizeof(*msgs); i++)
01034    {
01035       int err;
01036 
01037       if ((err = xdasd_parse_message(PMF_IMPORTED, 
01038             msgs[i].msgsz, msgs[i].msg, &parsed)) != 0)
01039       {
01040          xdasd_log(0, "%s: error %d at: %s(%d), loop %d.\n", 
01041                argv[0], err, __FILE__, __LINE__, i);
01042          exit(1);
01043       }
01044       if ((err = xdasd_mcache_put_msg(mc, parsed)) != 0)
01045       {
01046          xdasd_log(0, "%s: error %d at: %s(%d), loop %d.\n", 
01047                argv[0], err, __FILE__, __LINE__, i);
01048          exit(1);
01049       }
01050       xdasd_parse_free(parsed);
01051    }
01052 
01053    /* simulate a crash */
01054    xdasd_mcache_destroy(mc);
01055 
01056    /* simulate restart with data in the cache */
01057    mc = xdasd_mcache_create(cache_path);
01058 
01059    /* retrieve all remaining messages to see if they come out right
01060 
01061       NOTE: Because of the (simulated) crash, we were not able to update
01062       the cache pointers to the next output message, so we will retrieve 
01063       that same output message again after re-initialization - thus we
01064       start by decrementing j so we are comparing with the correct entry 
01065       in the table on the first pass. 
01066     */
01067    for (--j; j < sizeof(msgs)/sizeof(*msgs); j++)
01068    {
01069       parsed = xdasd_mcache_get_msg(mc);
01070       if (parsed == 0 || parsed->parsed[XDAS_FIELD_COUNT] 
01071                - parsed->parsed[0] - 1 != (int)msgs[j].msgsz 
01072             || strncmp(parsed->msg, msgs[j].msg, msgs[j].msgsz) != 0)
01073       {
01074          xdasd_log(0, "%s: corrupt cache detected at %s(%d), loop %d.\n", 
01075                argv[0], __FILE__, __LINE__, j);
01076          exit(1);                                  \
01077       }
01078       xdasd_parse_free(parsed);
01079    }
01080 
01081    /* We have to read past the end in order to update the out pointer
01082       in the cache and cause the last file to be deleted - but it had
01083       better not return data! */
01084    if ((parsed = xdasd_mcache_get_msg(mc)) != 0)
01085    {
01086       xdasd_log(0, "%s: read past end of cache detected at %s(%d).\n", 
01087             argv[0], __FILE__, __LINE__);
01088       exit(1);                                  \
01089    }
01090 
01091    /* cleanup */
01092    xdasd_mcache_destroy(mc);
01093 
01094    /* See if any cache files still exist (they shouldn't) */
01095    if ((dir = opendir(cache_path)) != 0)
01096    {
01097       while ((de = readdir(dir)) != 0)
01098          if (strncmp(de->d_name, MCACHE_BASE_FNAME, 
01099                sizeof(MCACHE_BASE_FNAME) - 1) == 0)
01100          {
01101             xdasd_log(0, "%s: file %s in cache didn't get removed.\n", 
01102                   argv[0], de->d_name);
01103             exit(1);
01104          }
01105       closedir(dir);
01106    }
01107    return 0;
01108 }
01109 
01110 #endif   /* XDASD_MCACHE_TEST */
01111 

Generated on Thu Aug 20 22:33:06 2009 for OpenXDAS by  doxygen 1.5.6