XrdOssLock.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                         X r d O s s L o c k . c c                          */
00004 /*                                                                            */
00005 /* (C) 2003 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*                DE-AC03-76-SFO0515 with the Deprtment of Energy             */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdOssLock.cc 34000 2010-06-21 06:49:56Z ganis $
00012 
00013 const char *XrdOssLockCVSID = "$Id: XrdOssLock.cc 34000 2010-06-21 06:49:56Z ganis $";
00014 
00015 /* The XrdOssSerialize() and XrdOssUnSerialize() routines are responsible for
00016    serializing access to directories and files. The current implementaion
00017    uses flock with a hiearchical system of locking. The defined protocol is:
00018 
00019    Stage in a file:
00020    1) Exclusively flock the DIR_LOCK file in the target directory.
00021    2) Create the shadow lock file.
00022    3) Exclusively flock the shadow lock file for the file to be staged in.
00023    4) Unlock the directory.
00024    5) Atomically copy the file to the local file system.
00025    6) Set the shadow lock file mtime to be the same as the base file's mtime.
00026    7) Unlock the lock file.
00027 
00028    Open a file:
00029    1) Exclusively flock the DIR_LOCK file in the target directory.
00030    2) Open the file.
00031    3) Unlock the directory.
00032    4) Do whatever with it.
00033 
00034    Stage out file:
00035    1) Exclusively flock the DIR_LOCK file in the target directory.
00036    2) Exclusively flock the shadow lock file for the file to be staged out.
00037    3) Unlock the directory.
00038    4) Copy the file to the target storage system.
00039    5) Check whether the file has been modified during the copy. If so, the
00040       copy is invalidated and the file needs to be copied again.
00041    6) Set the shadow lock file mtime to be the same as the base file's mtime.
00042    7) Unlock the lock file.
00043 
00044    Purge a file:
00045    1) Exclusively flock the DIR_LOCK file in the target directory.
00046    2) Attempt a share lock on the shadow lock file for the file to be purged.
00047       If someone else has a lock, skip to step 6.
00048    3) Check if the base file is open (e.g., via fuser). If it is, skip
00049       to step 5.
00050    4) Check if the lock file mtime >= base file mtime. If it is, purge the file
00051       as well as the corresponding lock file.
00052    5) Unlock the lock file.
00053    6) Unlock the directory lock.
00054 
00055 
00056    These routines are thread-safe if compiled with:
00057    AIX: -D_THREAD_SAFE
00058    SUN: -D_REENTRANT
00059 */
00060 
00061 /******************************************************************************/
00062 /*                               i n c l u d e s                              */
00063 /******************************************************************************/
00064   
00065 #include <unistd.h>
00066 #include <stdio.h>
00067 #include <sys/file.h>
00068 #include <sys/param.h>
00069 #include <sys/types.h>
00070 #include <sys/wait.h>
00071 #include <errno.h>
00072 #include <fcntl.h>
00073 #include <limits.h>
00074 #include <strings.h>
00075 #include <utime.h>
00076 
00077 #include "XrdOss/XrdOssApi.hh"
00078 #include "XrdOss/XrdOssConfig.hh"
00079 #include "XrdOss/XrdOssError.hh"
00080 #include "XrdOss/XrdOssLock.hh"
00081 #include "XrdSys/XrdSysError.hh"
00082 #include "XrdSys/XrdSysHeaders.hh"
00083 #include "XrdSys/XrdSysPlatform.hh"
00084 
00085 /******************************************************************************/
00086 /*           G l o b a l   E r r o r   R o u t i n g   O b j e c t            */
00087 /******************************************************************************/
00088   
00089 extern XrdSysError OssEroute;
00090 
00091 /******************************************************************************/
00092 /*                               d e f i n e s                                */
00093 /******************************************************************************/
00094 
00095 #define XrdOssLKFNAME  "DIR_LOCK"
00096 #define XrdOssLKSUFFIX ".lock"
00097 #define XrdOssLKTRIES  300
00098 #define XrdOssLKWAIT   1
00099 
00100 /******************************************************************************/
00101 /*                         o o s s _ S e r i a l i z e                        */
00102 /******************************************************************************/
00103 
00104 /*In:  fn      - The path to be locked.
00105        lkwant  - Locking options:
00106                  XrdOssDIR      - Lock the corresponding directory.
00107                  XrdOssFILE     - Lock the target file.
00108                  XrdOssNOWAIT   - Do not block.
00109                  XrdOssEXC      - Exclusive lock (the default).
00110                  XrdOssSHR      - Shared lock.
00111                  XrdOssRETIME   - Adjust time for relativistic creation effects
00112 
00113    Out: XrdOssOK upon success; -errno,otherwise.
00114 */
00115 
00116 int XrdOssLock::Serialize(const char *fn, int lkwant)
00117 {
00118     char lkbuff[MAXPATHLEN+sizeof(XrdOssLKFNAME)];
00119     int rc;
00120 
00121 // Check if this object is already in use
00122 //
00123    if (lkfd >= 0) 
00124       return OssEroute.Emsg("Serialize",-XRDOSS_E8014,"lock",lkbuff);
00125 
00126 // Create the lock file name that we will lock as requested.
00127 //
00128     if ((rc = Build_LKFN(lkbuff, sizeof(lkbuff), fn, lkwant))) return rc;
00129 
00130 // Open the file in write mode (create it if not there).
00131 //
00132     do { lkfd = open(lkbuff, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);}
00133         while( lkfd < 0 && errno == EINTR);
00134     if ( lkfd < 0) 
00135        {if (ENOENT != (rc = errno))
00136            OssEroute.Emsg("Serialize",rc,"serially open",lkbuff);
00137         return -rc;
00138        }
00139     fcntl(lkfd, F_SETFD, FD_CLOEXEC);
00140 
00141 // If we should adjust time, do so now
00142 //
00143    if (lkwant & XrdOssRETIME)
00144       {struct stat    buf;
00145        struct utimbuf times;
00146        if (!(rc = stat(fn, &buf)))
00147           {times.actime =  buf.st_atime;
00148            times.modtime = buf.st_mtime-63;
00149            rc = utime(lkbuff, (const struct utimbuf *)&times);
00150           }
00151        if (rc) {rc = errno; close(lkfd); lkfd = -1;
00152                 return OssEroute.Emsg("Serialize",rc,"retime",lkbuff);
00153                }
00154       }
00155 
00156 // Now lock the file and return the file descriptor.
00157 //
00158     if ((rc = XLock(lkfd, lkwant)))
00159        {char *mp;
00160         close(lkfd); lkfd = -1;
00161         if (rc == EWOULDBLOCK) return -EWOULDBLOCK;
00162         if (lkwant & XrdOssRETIME)
00163            mp = (lkwant&XrdOssSHR ? (char *)"rt shr lk":(char *)"rt exc lk");
00164            else mp = (lkwant & XrdOssSHR ? (char *)"shr lk":(char *)"exc lk");
00165         return OssEroute.Emsg("Serialize", rc, mp, lkbuff);
00166         return -XRDOSS_E8015;
00167        }
00168     return XrdOssOK;
00169 }
00170 
00171 /******************************************************************************/
00172 /*                        o o s s _ N o S e r i a l i z e                     */
00173 /******************************************************************************/
00174 
00175 /*In:  fn      - The filename whose lockfile is to be deleted.
00176        ftype   - Lock type (one must be specified):
00177                  XrdOssDIR      - Directory lock.
00178                  XrdOssFILE     - File lock.
00179 
00180    Out: Upon success, zero is returned.
00181         Otherwise, a negative error code is returned corresponding to -errno.
00182 */
00183 
00184 int XrdOssLock::NoSerialize(const char *fn, int ftype)
00185 {
00186     char lkbuff[MAXPATHLEN+sizeof(XrdOssLKFNAME)];
00187     int rc;
00188 
00189 // Verify that a lock filetype has been specified.
00190 //
00191     if (!(ftype & (XrdOssDIR | XrdOssFILE)))
00192        return OssEroute.Emsg("NoSerialize", -XRDOSS_E8016,
00193                                "unserialize fname", (char *)fn);
00194 
00195 // Create the lock file name that we will lock as requested.
00196 //
00197     if ((rc = Build_LKFN(lkbuff, sizeof(lkbuff), fn, ftype))) return rc;
00198 
00199 // Unlink the file.
00200 //
00201     if (unlink(lkbuff))
00202        {rc = errno;
00203         if (rc != ENOENT) 
00204            return OssEroute.Emsg("NoSerialize", -rc,
00205                                    "unserialize lkfname", (char *)fn);
00206        }
00207     return XrdOssOK;
00208 }
00209 
00210 /******************************************************************************/
00211 /*                   o o s s _ R e S e r i a l i z e                          */
00212 /******************************************************************************/
00213 
00214 /*In:  oldname - The old name of the base file being renamed.
00215        newname - The new name of the base file.
00216 
00217   Out: If the corresponding lock file is rename is successfully renamed,
00218        zero is returned. Otherwise -errno is returned.
00219 
00220  Note: The correspodning directory must have been locked by the caller!
00221 */
00222 
00223 int XrdOssLock::ReSerialize(const char *oldname, const char *newname)
00224 {
00225     int rc = 0;
00226     char Path_Old[MAXPATHLEN+1];
00227     char Path_New[MAXPATHLEN+1];
00228 
00229 // Build old and new lock file names
00230 //
00231    if ((rc = Build_LKFN(Path_Old, sizeof(Path_Old), oldname, XrdOssFILE)))
00232       return rc;
00233    if ((rc = Build_LKFN(Path_New, sizeof(Path_New), newname, XrdOssFILE)))
00234       return rc;
00235 
00236 // Rename the lock file.
00237 //
00238    if (rename(Path_Old, Path_New))
00239       {rc = errno;
00240        if (rc != ENOENT) OssEroute.Emsg("ReSerialize",rc,"reserialize",Path_Old);
00241           else rc = 0;
00242       }
00243    return -rc;
00244 }
00245 
00246 /******************************************************************************/
00247 /*                   o o s s _ U n S e r i a l i z e                          */
00248 /******************************************************************************/
00249 
00250 /*In:  opts    - Unlocking options:
00251                  XrdOssLEAVE    - leave the underlying filehandle open.
00252                  XrdOssREGRADE  - Don't release the lock. Instead do an upgrade
00253                                  or a downgrade (default is to release lock).
00254                  XrdOssRETRY    - release the lock and pause (if !XrdOssREGRADE),
00255                                  then try to obtain the lock again with
00256                                  XrdOssSerialize() options.
00257 */
00258 
00259 int XrdOssLock::UnSerialize(int opts)
00260 {
00261     int maxtry = XrdOssLKTRIES;
00262     int xopts, rc, dosleep = 1;
00263     const struct timespec naptime = {XrdOssLKWAIT, 0};
00264 
00265 // Check if we havenything reallly locked
00266 //
00267    if (lkfd < 0) 
00268       return OssEroute.Emsg("UnSerialize",-XRDOSS_E8017,"unserialize lock");
00269 
00270 // Release the lock if we need to.
00271 //
00272    if (!(opts & XrdOssREGRADE)) XLock(lkfd, 0);
00273       else dosleep = 0;
00274 
00275 // Based on execution option, perform the required action.
00276 //
00277     xopts = opts & (XrdOssLEAVE | XrdOssRETRY);
00278     switch(xopts)
00279          {case XrdOssLEAVE: break;
00280           case XrdOssRETRY: do {if (dosleep) nanosleep(&naptime, 0);
00281                                if (! (rc = XLock(lkfd, opts)) ) break;
00282                                dosleep = 1;
00283                               } while( rc == EWOULDBLOCK && 
00284                                       !(opts & XrdOssNOWAIT) && maxtry--);
00285                            return -rc;
00286           default:         close(lkfd); lkfd = -1;
00287                            break;
00288          }
00289     return XrdOssOK;
00290 }
00291 
00292 /******************************************************************************/
00293 /*                            B u i l d _ L K F N                             */
00294 /******************************************************************************/
00295 
00296 int XrdOssLock::Build_LKFN(char *buff, int blen, const char *fn, int ftype)
00297 {  int i;
00298 
00299 // Verify that input filename is not too large.
00300 //
00301    i = strlen(fn);
00302    if (i + (ftype & XrdOssFILE ? (int)sizeof(XrdOssLKSUFFIX) 
00303                                : (int)sizeof(XrdOssLKFNAME)+1) > blen)
00304       return OssEroute.Emsg("Build_LKFN", -ENAMETOOLONG,
00305                               "generate lkfname", (char *)fn);
00306 
00307 // Create the lock file name that we will lock in exclusive mode.
00308 //
00309    strcpy(buff, fn);
00310    if (ftype & XrdOssFILE) strcat(buff, XrdOssLKSUFFIX);
00311       else {
00312             for (i = i-1; i >= 0 && buff[i] != '/'; i--){}
00313             if (i <= 0) {strcpy(buff, "./"); i = 1;}
00314             strcpy(&buff[i+1], XrdOssLKFNAME);
00315            }
00316 
00317 // All done.
00318 //
00319    return XrdOssOK;
00320 }
00321 
00322 /******************************************************************************/
00323 /*                                X L o c k                                   */
00324 /******************************************************************************/
00325 
00326 int XrdOssLock::XLock(int lkFD, int opts)
00327 {
00328     FLOCK_t lock_args;
00329 
00330 // Make sure we have a lock outstanding
00331 //
00332     if (lkFD < 0) return XrdOssOK;
00333 
00334 // Establish locking options
00335 //
00336     bzero(&lock_args, sizeof(lock_args));
00337     if (opts & XrdOssSHR) lock_args.l_type = F_RDLCK;
00338        else if (opts & XrdOssEXC) lock_args.l_type = F_WRLCK;
00339                else lock_args.l_type = F_UNLCK;
00340 
00341 // Perform action.
00342 //
00343     if (fcntl(lkFD, (opts & XrdOssNOWAIT ? F_SETLK : F_SETLKW),
00344                     &lock_args)) return errno;
00345     return XrdOssOK;
00346 }

Generated on Tue Jul 5 14:46:47 2011 for ROOT_528-00b_version by  doxygen 1.5.1