00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdOssMioCVSID = "$Id: XrdOssMio.cc 30949 2009-11-02 16:37:58Z ganis $";
00014
00015 #include <unistd.h>
00016 #include <stdio.h>
00017 #include <sys/param.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020
00021 #if defined(_POSIX_MAPPED_FILES)
00022 #include <sys/mman.h>
00023 #endif
00024
00025 #include "XrdSys/XrdSysPthread.hh"
00026 #include "XrdOss/XrdOssMio.hh"
00027 #include "XrdOss/XrdOssMioFile.hh"
00028 #include "XrdOss/XrdOssTrace.hh"
00029
00030
00031
00032
00033
00034 XrdOucHash<XrdOssMioFile> XrdOssMio::MM_Hash;
00035
00036 XrdSysMutex XrdOssMio::MM_Mutex;
00037
00038 XrdOssMioFile *XrdOssMio::MM_Perm = 0;
00039 XrdOssMioFile *XrdOssMio::MM_Idle = 0;
00040 XrdOssMioFile *XrdOssMio::MM_IdleLast = 0;
00041
00042 char XrdOssMio::MM_on = 1;
00043 char XrdOssMio::MM_chkmap = 0;
00044 char XrdOssMio::MM_chklok = 0;
00045 char XrdOssMio::MM_chkkeep = 0;
00046 char XrdOssMio::MM_chk = 0;
00047 char XrdOssMio::MM_okmlock = 1;
00048 char XrdOssMio::MM_preld = 0;
00049 long long XrdOssMio::MM_pagsz = (long long)sysconf(_SC_PAGESIZE);
00050 #ifdef __macos__
00051 long long XrdOssMio::MM_pages = 1024*1024*1024;
00052 #else
00053 long long XrdOssMio::MM_pages = (long long)sysconf(_SC_PHYS_PAGES);
00054 #endif
00055 long long XrdOssMio::MM_max = MM_pagsz*MM_pages/2;
00056 long long XrdOssMio::MM_inuse = 0;
00057
00058 extern XrdSysError OssEroute;
00059
00060 extern XrdOucTrace OssTrace;
00061
00062
00063
00064
00065
00066 void XrdOssMio::Display(XrdSysError &Eroute)
00067 {
00068 char buff[1080];
00069 snprintf(buff, sizeof(buff), " oss.memfile %s%s%s%s%s max %lld",
00070 (MM_on ? "" : "off "),
00071 (MM_preld ? "preload" : ""),
00072 (MM_chklok ? "check lock " : ""),
00073 (MM_chkmap ? "check map " : ""),
00074 (MM_chkkeep ? "check keep" : ""), MM_max);
00075 Eroute.Say(buff);
00076 }
00077
00078
00079
00080
00081
00082 int XrdOssMio::getOpts(char *path, int popts)
00083 {
00084 struct stat statb;
00085 char buff[MAXPATHLEN+16], *bsfx = buff+strlen(path);
00086
00087
00088
00089 if (MM_chklok && !(popts & OSSMIO_MLOK))
00090 {strcpy(bsfx, ".mlock");
00091 if (!stat(buff, &statb)) popts |= OSSMIO_MLOK;
00092 }
00093 else if (MM_chkmap && !(popts & OSSMIO_MMAP))
00094 {strcpy(bsfx, ".mmap");
00095 if (!stat(buff, &statb)) popts |= OSSMIO_MMAP;
00096 }
00097 if (MM_chkkeep && !(popts & OSSMIO_MPRM))
00098 {strcpy(bsfx, ".mkeep");
00099 if (!stat(buff, &statb)) popts |= OSSMIO_MPRM;
00100 }
00101
00102 return popts;
00103 }
00104
00105
00106
00107
00108
00109 XrdOssMioFile *XrdOssMio::Map(char *path, int fd, int opts)
00110 {
00111 #if defined(_POSIX_MAPPED_FILES)
00112 EPNAME("MioMap");
00113 XrdSysMutexHelper mapMutex;
00114 struct stat statb;
00115 XrdOssMioFile *mp;
00116 void *thefile;
00117 char hashname[64];
00118
00119
00120
00121 if (fstat(fd, &statb))
00122 {OssEroute.Emsg("Mio", errno, "fstat file", path);
00123 return 0;
00124 }
00125
00126
00127
00128 XrdOucTrace::bin2hex((char *)&statb.st_dev,
00129 int(sizeof(statb.st_dev)), hashname);
00130 XrdOucTrace::bin2hex((char *)&statb.st_ino, int(sizeof(statb.st_ino)),
00131 hashname+(sizeof(statb.st_dev)*2));
00132
00133
00134
00135 mapMutex.Lock(&MM_Mutex);
00136
00137
00138
00139 if ((mp = MM_Hash.Find(hashname)))
00140 {DEBUG("Reusing mmap; usecnt=" <<mp->inUse <<" path=" <<path);
00141 if (!(mp->Status & OSSMIO_MPRM) && !mp->inUse) Reclaim(mp);
00142 mp->inUse++;
00143 return mp;
00144 }
00145
00146
00147
00148 if (MM_inuse + statb.st_size > MM_max)
00149 {if (!Reclaim(statb.st_size))
00150 {OssEroute.Emsg("Mio", "Unable to reclaim enough storage to mmap",path);
00151 return 0;
00152 }
00153 }
00154 MM_inuse += statb.st_size;
00155
00156
00157
00158 if ((thefile = mmap(0,statb.st_size,PROT_READ,MAP_PRIVATE,fd,0))==MAP_FAILED)
00159 {OssEroute.Emsg("Mio", errno, "mmap file", path);
00160 return 0;
00161 } else {DEBUG("mmap " <<statb.st_size <<" bytes for " <<path);}
00162
00163
00164
00165 if (MM_okmlock && (opts & OSSMIO_MLOK))
00166 {if (mlock((char *)thefile, statb.st_size))
00167 { if (errno == ENOSYS)
00168 {OssEroute.Emsg("Mio","mlock() not supported; feature disabled.");
00169 MM_okmlock = 0;
00170 }
00171 else if (errno == EPERM)
00172 {OssEroute.Emsg("Mio","Not privileged for mlock(); feature disabled.");
00173 MM_okmlock = 0;
00174 }
00175 else OssEroute.Emsg("Mio", errno, "mlock file", path);
00176 } else {DEBUG("Locked " <<statb.st_size <<" bytes for " <<path);}
00177 }
00178
00179
00180
00181 if (!(mp = new XrdOssMioFile(hashname)))
00182 {OssEroute.Emsg("Mio", "Unable to allocate mmap file object for", path);
00183 munmap((char *)thefile, statb.st_size);
00184 return 0;
00185 }
00186
00187
00188
00189 mp->Base = thefile;
00190 mp->Size = statb.st_size;
00191 mp->Dev = statb.st_dev;
00192 mp->Ino = statb.st_ino;
00193 mp->Status = opts;
00194
00195
00196
00197 if (MM_Hash.Add(hashname, mp))
00198 {OssEroute.Emsg("Mio", "Hash add failed for", path);
00199 munmap((char *)thefile, statb.st_size);
00200 delete mp;
00201 return 0;
00202 }
00203
00204
00205
00206 if (opts & OSSMIO_MPRM)
00207 {mp->Next = MM_Perm; MM_Perm = mp;
00208 DEBUG("Placed file on permanent queue " <<path);
00209 }
00210
00211
00212
00213 if (MM_preld && mp->inUse == 1)
00214 {pthread_t tid;
00215 int retc;
00216 mp->inUse++;
00217 if ((retc = XrdSysThread::Run(&tid, preLoad, (void *)mp)) < 0)
00218 {OssEroute.Emsg("Mio", retc, "creating mmap preload thread");
00219 mp->inUse--;
00220 }
00221 else DEBUG("started mmap preload thread; tid=" <<(unsigned long)tid);
00222 }
00223
00224
00225
00226 return mp;
00227 #else
00228 return 0;
00229 #endif
00230 }
00231
00232
00233
00234
00235
00236 void *XrdOssMio::preLoad(void *arg)
00237 {
00238 XrdOssMioFile *mp = (XrdOssMioFile *)arg;
00239 char *Base = (char *)(mp->Base);
00240 char *Bend = Base + mp->Size;
00241 char Byte;
00242
00243
00244
00245 while(Base < Bend) {Byte = *Base; Base += MM_pagsz;}
00246
00247
00248
00249 Recycle(mp);
00250 return (void *)0;
00251 }
00252
00253
00254
00255
00256
00257
00258
00259 int XrdOssMio::Reclaim(off_t amount)
00260 {
00261 EPNAME("MioReclaim");
00262 XrdOssMioFile *mp;
00263 DEBUG("Trying to reclaim " <<amount <<" bytes.");
00264
00265
00266
00267 while((mp = MM_Idle) && amount > 0)
00268 {MM_Idle = mp->Next;
00269 MM_inuse -= mp->Size;
00270 amount -= mp->Size;
00271 MM_Hash.Del(mp->HashName);
00272 }
00273
00274
00275
00276 return amount <= 0;
00277 }
00278
00279
00280
00281 int XrdOssMio::Reclaim(XrdOssMioFile *mp)
00282 {
00283 EPNAME("MioReclaim");
00284 XrdOssMioFile *pmp = 0, *cmp = MM_Idle;
00285
00286
00287
00288 while(cmp && mp != cmp) {pmp = cmp; cmp = cmp->Next;}
00289
00290
00291
00292 if (cmp)
00293 {if (pmp) pmp->Next = mp->Next;
00294 else MM_Idle = mp->Next;
00295 if (MM_IdleLast == cmp) MM_IdleLast = pmp;
00296 }
00297 else {DEBUG("Cannot find mapping for " <<mp->Dev <<':' <<mp->Ino);}
00298
00299 return (cmp != 0);
00300 }
00301
00302
00303
00304
00305
00306 void XrdOssMio::Recycle(XrdOssMioFile *mp)
00307 {
00308 XrdSysMutexHelper mmMutex(&MM_Mutex);
00309
00310
00311
00312 mp->inUse--;
00313 if (mp->inUse < 0)
00314 {OssEroute.Emsg("Mio", "MM usecount underflow for ", mp->HashName);
00315 mp->inUse = 0;
00316 } else if (mp->inUse > 0) return;
00317
00318
00319
00320 if (!(mp->Status & OSSMIO_MPRM))
00321 {if (MM_IdleLast) MM_IdleLast->Next = mp;
00322 else MM_Idle = mp;
00323 MM_IdleLast = mp;
00324 mp->Next = 0;
00325 }
00326 }
00327
00328
00329
00330
00331
00332 void XrdOssMio::Set(int V_on, int V_preld, int V_chklok,
00333 int V_chkmap, int V_chkkeep)
00334 {
00335 if (V_on >= 0) MM_on = (char)V_on;
00336 if (V_preld >= 0) MM_preld = (char)V_preld;
00337 if (V_chklok >= 0) MM_chklok = (char)V_chklok;
00338 if (V_chkmap >= 0) MM_chkmap = (char)V_chkmap;
00339 if (V_chkkeep >= 0) MM_chkkeep = (char)V_chkkeep;
00340 MM_chk = MM_chklok | MM_chkmap | MM_chkkeep;
00341 }
00342
00343 void XrdOssMio::Set(long long V_max)
00344 {
00345 if (V_max > 0) MM_max = V_max;
00346 else if (V_max < 0) MM_max = MM_pagsz*MM_pages*(-V_max)/100;
00347 }
00348
00349
00350
00351
00352
00353 XrdOssMioFile::~XrdOssMioFile()
00354 {
00355 #if defined(_POSIX_MAPPED_FILES)
00356 munmap((char *)Base, Size);
00357 #endif
00358 }