• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Store.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "libts.h"
00025 #include "P_Cache.h"
00026 #include "I_Layout.h"
00027 
00028 #if HAVE_SYS_PARAM_H
00029 #include <sys/param.h>
00030 #endif
00031 
00032 #if HAVE_SYS_DISK_H
00033 #include <sys/disk.h>
00034 #endif
00035 
00036 #if HAVE_SYS_DISKLABEL_H
00037 #include <sys/disklabel.h>
00038 #endif
00039 
00040 // Global
00041 Store theStore;
00042 
00043 //
00044 // Store
00045 //
00046 
00047 char const Store::VOLUME_KEY[] = "volume";
00048 char const Store::HASH_BASE_STRING_KEY[] = "id";
00049 
00050 Ptr<ProxyMutex> tmp_p;
00051 Store::Store():n_disks(0), disk(NULL)
00052 #if TS_USE_INTERIM_CACHE == 1
00053               ,n_interim_disks(0), interim_disk(NULL)
00054 #endif
00055 {
00056 }
00057 
00058 int
00059 initialize_store()
00060 {
00061   return theStore.read_config()? -1 : 0;
00062 }
00063 
00064 void
00065 Store::add(Span * ds)
00066 {
00067   extend(n_disks + 1);
00068   disk[n_disks - 1] = ds;
00069 }
00070 
00071 void
00072 Store::add(Store & s)
00073 {
00074   // assume on different disks
00075   for (unsigned i = 0; i < s.n_disks; i++) {
00076     add(s.disk[i]);
00077   }
00078   s.n_disks = 0;
00079   s.delete_all();
00080 }
00081 
00082 
00083 
00084 // should be changed to handle offset in more general
00085 // case (where this is not a free of a "just" allocated
00086 // store
00087 void
00088 Store::free(Store & s)
00089 {
00090   for (unsigned i = 0; i < s.n_disks; i++) {
00091     for (Span * sd = s.disk[i]; sd; sd = sd->link.next) {
00092       for (unsigned j = 0; j < n_disks; j++)
00093         for (Span * d = disk[j]; d; d = d->link.next)
00094           if (!strcmp(sd->pathname, d->pathname)) {
00095             if (sd->offset < d->offset)
00096               d->offset = sd->offset;
00097             d->blocks += sd->blocks;
00098             goto Lfound;
00099           }
00100       ink_release_assert(!"Store::free failed");
00101     Lfound:;
00102     }
00103   }
00104 }
00105 
00106 void
00107 Store::sort()
00108 {
00109   Span **vec = (Span **) alloca(sizeof(Span *) * n_disks);
00110   memset(vec, 0, sizeof(Span *) * n_disks);
00111   for (unsigned i = 0; i < n_disks; i++) {
00112     vec[i] = disk[i];
00113     disk[i] = NULL;
00114   }
00115 
00116   // sort by device
00117 
00118   unsigned n = 0;
00119   for (unsigned i = 0; i < n_disks; i++) {
00120     for (Span * sd = vec[i]; sd; sd = vec[i]) {
00121       vec[i] = vec[i]->link.next;
00122       for (unsigned d = 0; d < n; d++) {
00123         if (sd->disk_id == disk[d]->disk_id) {
00124           sd->link.next = disk[d];
00125           disk[d] = sd;
00126           goto Ldone;
00127         }
00128       }
00129       disk[n++] = sd;
00130     Ldone:;
00131     }
00132   }
00133   n_disks = n;
00134 
00135   // sort by pathname x offset
00136 
00137   for (unsigned i = 0; i < n_disks; i++) {
00138   Lagain:
00139     Span * prev = 0;
00140     for (Span * sd = disk[i]; sd;) {
00141       Span *next = sd->link.next;
00142       if (next &&
00143           ((strcmp(sd->pathname, next->pathname) < 0) ||
00144            (!strcmp(sd->pathname, next->pathname) && sd->offset > next->offset))) {
00145         if (!prev) {
00146           disk[i] = next;
00147           sd->link.next = next->link.next;
00148           next->link.next = sd;
00149         } else {
00150           prev->link.next = next;
00151           sd->link.next = next->link.next;
00152           next->link.next = sd;
00153         }
00154         goto Lagain;
00155       }
00156       prev = sd;
00157       sd = next;
00158     }
00159   }
00160 
00161   // merge adjacent spans
00162 
00163   for (unsigned i = 0; i < n_disks; i++) {
00164     for (Span * sd = disk[i]; sd;) {
00165       Span *next = sd->link.next;
00166       if (next && !strcmp(sd->pathname, next->pathname)) {
00167         if (!sd->file_pathname) {
00168           sd->blocks += next->blocks;
00169         } else if (next->offset <= sd->end()) {
00170           if (next->end() >= sd->end())
00171             sd->blocks += (next->end() - sd->end());
00172         } else {
00173           sd = next;
00174           continue;
00175         }
00176         sd->link.next = next->link.next;
00177         delete next;
00178         sd = sd->link.next;
00179       } else
00180         sd = next;
00181     }
00182   }
00183 }
00184 
00185 int
00186 Span::path(char *filename, int64_t * aoffset, char *buf, int buflen)
00187 {
00188   ink_assert(!aoffset);
00189   Span *ds = this;
00190 
00191   if ((strlen(ds->pathname) + strlen(filename) + 2) > (size_t)buflen)
00192     return -1;
00193   if (!ds->file_pathname) {
00194     ink_filepath_make(buf, buflen, ds->pathname, filename);
00195   } else {
00196     ink_strlcpy(buf, ds->pathname, buflen);
00197   }
00198 
00199   return strlen(buf);
00200 }
00201 
00202 void
00203 Span::hash_base_string_set(char const* s)
00204 {
00205   hash_base_string = s ? ats_strdup(s) : NULL;
00206 }
00207 
00208 void
00209 Span::volume_number_set(int n)
00210 {
00211   forced_volume_num = n;
00212 }
00213 
00214 void
00215 Store::delete_all()
00216 {
00217   for (unsigned i = 0; i < n_disks; i++) {
00218     if (disk[i])
00219       delete disk[i];
00220   }
00221   n_disks = 0;
00222   ats_free(disk);
00223   disk = NULL;
00224 }
00225 
00226 Store::~Store()
00227 {
00228   delete_all();
00229 }
00230 
00231 Span::~Span()
00232 {
00233   if (link.next)
00234     delete link.next;
00235 }
00236 
00237 inline int
00238 get_int64(int fd, int64_t & data)
00239 {
00240   char buf[PATH_NAME_MAX + 1];
00241   if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
00242     return (-1);
00243   // the above line will guarantee buf to be no longer than PATH_NAME_MAX
00244   // so the next statement should be a safe use of sscanf
00245   // coverity[secure_coding]
00246   if (sscanf(buf, "%" PRId64 "", &data) != 1) {
00247     return (-1);
00248   }
00249   return 0;
00250 }
00251 
00252 int
00253 Store::remove(char *n)
00254 {
00255   bool found = false;
00256 Lagain:
00257   for (unsigned i = 0; i < n_disks; i++) {
00258     Span *p = NULL;
00259     for (Span * sd = disk[i]; sd; sd = sd->link.next) {
00260       if (!strcmp(n, sd->pathname)) {
00261         found = true;
00262         if (p)
00263           p->link.next = sd->link.next;
00264         else
00265           disk[i] = sd->link.next;
00266         sd->link.next = NULL;
00267         delete sd;
00268         goto Lagain;
00269       }
00270       p = sd;
00271     }
00272   }
00273   return found ? 0 : -1;
00274 }
00275 
00276 const char *
00277 Store::read_config(int fd)
00278 {
00279   int n_dsstore = 0;
00280   int ln = 0;
00281   int i = 0;
00282   const char *err = NULL;
00283   Span *sd = NULL, *cur = NULL;
00284   Span *ns;
00285 
00286   // Get pathname if not checking file
00287 
00288   if (fd < 0) {
00289     ats_scoped_str storage_path(RecConfigReadConfigPath("proxy.config.cache.storage_filename", "storage.config"));
00290 
00291     Debug("cache_init", "Store::read_config, fd = -1, \"%s\"", (const char *)storage_path);
00292     fd = ::open(storage_path, O_RDONLY);
00293     if (fd < 0) {
00294       err = "error on open";
00295       goto Lfail;
00296     }
00297   }
00298   // For each line
00299 
00300   char line[1024];
00301   int len;
00302   while ((len = ink_file_fd_readline(fd, sizeof(line), line)) > 0) {
00303     char const* path;
00304     char const* seed = 0;
00305     // update lines
00306 
00307     ++ln;
00308 
00309     // Because the SimpleTokenizer is a bit too simple, we have to normalize whitespace.
00310     for ( char *spot = line, *limit = line+len ; spot < limit ; ++spot )
00311       if (ParseRules::is_space(*spot)) *spot = ' '; // force whitespace to literal space.
00312 
00313     SimpleTokenizer tokens(line, ' ', SimpleTokenizer::OVERWRITE_INPUT_STRING);
00314 
00315     // skip comments and blank lines
00316     path = tokens.getNext();
00317     if (0 == path || '#' == path[0])
00318       continue;
00319 
00320     // parse
00321     Debug("cache_init", "Store::read_config: \"%s\"", path);
00322 
00323     int64_t size = -1;
00324     int volume_num = -1;
00325     char const* e;
00326     while (0 != (e = tokens.getNext())) {
00327       if (ParseRules::is_digit(*e)) {
00328         if ((size = ink_atoi64(e)) <= 0) {
00329           err = "error parsing size";
00330           goto Lfail;
00331         }
00332       } else if (0 == strncasecmp(HASH_BASE_STRING_KEY, e, sizeof(HASH_BASE_STRING_KEY)-1)) {
00333         e += sizeof(HASH_BASE_STRING_KEY) - 1;
00334         if ('=' == *e) ++e;
00335         if (*e && !ParseRules::is_space(*e))
00336           seed = e;
00337       } else if (0 == strncasecmp(VOLUME_KEY, e, sizeof(VOLUME_KEY)-1)) {
00338         e += sizeof(VOLUME_KEY) - 1;
00339         if ('=' == *e) ++e;
00340         if (!*e || !ParseRules::is_digit(*e) || 0 >= (volume_num = ink_atoi(e))) {
00341           err = "error parsing volume number";
00342           goto Lfail;
00343         }
00344       }
00345     }
00346 
00347     char *pp = Layout::get()->relative(path);
00348     ns = new Span;
00349     Debug("cache_init", "Store::read_config - ns = new Span; ns->init(\"%s\",%" PRId64 "), forced volume=%d%s%s",
00350           pp, size, volume_num, seed ? " id=" : "", seed ? seed : "");
00351     if ((err = ns->init(pp, size))) {
00352       RecSignalWarning(REC_SIGNAL_SYSTEM_ERROR, "could not initialize storage \"%s\" [%s]", pp, err);
00353       Debug("cache_init", "Store::read_config - could not initialize storage \"%s\" [%s]", pp, err);
00354       delete ns;
00355       ats_free(pp);
00356       continue;
00357     }
00358     ats_free(pp);
00359     n_dsstore++;
00360 
00361     // Set side values if present.
00362     if (seed) ns->hash_base_string_set(seed);
00363     if (volume_num > 0) ns->volume_number_set(volume_num);
00364 
00365     // new Span
00366     {
00367       Span *prev = cur;
00368       cur = ns;
00369       if (!sd)
00370         sd = cur;
00371       else
00372         prev->link.next = cur;
00373     }
00374   }
00375 
00376   // count the number of disks
00377   extend(n_dsstore);
00378   cur = sd;
00379   while (cur) {
00380     Span* next = cur->link.next;
00381     cur->link.next = NULL;
00382     disk[i++] = cur;
00383     cur = next;
00384   }
00385   sd = 0; // these are all used.
00386   sort();
00387   ::close(fd);
00388   return NULL;
00389 
00390 Lfail:
00391   // Do clean up.
00392   ::close(fd);
00393   if (sd)
00394     delete sd;
00395 
00396   return err;
00397 }
00398 
00399 #if TS_USE_INTERIM_CACHE == 1
00400 const char *
00401 Store::read_interim_config() {
00402   char p[PATH_NAME_MAX + 1];
00403   Span *sd = NULL;
00404   Span *ns;
00405   int interim_store = 0;
00406   REC_ReadConfigString(p, "proxy.config.cache.interim.storage", PATH_NAME_MAX);
00407 
00408   char *n = p;
00409   int sz = strlen(p);
00410 
00411   const char *err = NULL;
00412   for (int len = 0; n < p + sz; n += len + 1) {
00413     char *e = strpbrk(n, " \t\n");
00414     len = e ? e - n : strlen(n);
00415     n[len] = '\0';
00416     ns = new Span;
00417     if ((err = ns->init(n, -1))) {
00418       RecSignalWarning(REC_SIGNAL_SYSTEM_ERROR, "could not initialize storage \"%s\" [%s]", n, err);
00419       Debug("cache_init", "Store::read_interim_config - could not initialize storage \"%s\" [%s]", n, err);
00420       delete ns;
00421       continue;
00422     }
00423     ns->link.next = sd;
00424     sd = ns;
00425     interim_store++;
00426   }
00427 
00428   n_interim_disks = interim_store;
00429   interim_disk = (Span **) ats_malloc(interim_store * sizeof(Span *));
00430   {
00431     int i = 0;
00432     while (sd) {
00433       ns = sd;
00434       sd = sd->link.next;
00435       ns->link.next = NULL;
00436       interim_disk[i++] = ns;
00437     }
00438   }
00439   return NULL;
00440 }
00441 #endif
00442 
00443 int
00444 Store::write_config_data(int fd)
00445 {
00446   for (unsigned i = 0; i < n_disks; i++)
00447     for (Span * sd = disk[i]; sd; sd = sd->link.next) {
00448       char buf[PATH_NAME_MAX + 64];
00449       snprintf(buf, sizeof(buf), "%s %" PRId64 "\n", sd->pathname.get(), (int64_t) sd->blocks * (int64_t) STORE_BLOCK_SIZE);
00450       if (ink_file_fd_writestring(fd, buf) == -1)
00451         return (-1);
00452     }
00453   return 0;
00454 }
00455 
00456 #if defined(freebsd) || defined(darwin) || defined(openbsd)
00457 
00458 const char *
00459 Span::init(char *an, int64_t size)
00460 {
00461   int devnum = 0;
00462   const char *err = NULL;
00463   int ret = 0;
00464 
00465   is_mmapable_internal = true;
00466 
00467   // handle symlinks
00468 
00469   char *n = NULL;
00470   int n_len = 0;
00471   char real_n[PATH_NAME_MAX];
00472 
00473   if ((n_len = readlink(an, real_n, sizeof(real_n) - 1)) > 0) {
00474     real_n[n_len] = 0;
00475     if (*real_n != '/') {
00476       char *rs = strrchr(an, '/');
00477       int l = 2;
00478       const char *ann = "./";
00479 
00480       if (rs) {
00481         ann = an;
00482         l = (rs - an) + 1;
00483       }
00484       memmove(real_n + l, real_n, strlen(real_n) + 1);
00485       memcpy(real_n, ann, l);
00486     }
00487     n = real_n;
00488   } else {
00489     n = an;
00490   }
00491 
00492   // stat the file system
00493 
00494   struct stat s;
00495   if ((ret = stat(n, &s)) < 0) {
00496     Warning("unable to stat '%s': %d %d, %s", n, ret, errno, strerror(errno));
00497     return "error stat of file";
00498   }
00499 
00500   ats_scoped_fd fd(socketManager.open(n, O_RDONLY));
00501   if (!fd) {
00502     Warning("unable to open '%s': %s", n, strerror(errno));
00503     return "unable to open";
00504   }
00505 
00506   struct statvfs fs;
00507   if ((ret = fstatvfs(fd, &fs)) < 0) {
00508     Warning("unable to statvfs '%s': %d %d, %s", n, ret, errno, strerror(errno));
00509     return "unable to statvfs";
00510   }
00511 
00512   hw_sector_size = fs.f_bsize;
00513   int64_t fsize = (int64_t) fs.f_blocks * (int64_t) fs.f_bsize;
00514 
00515   switch ((s.st_mode & S_IFMT)) {
00516 
00517   case S_IFBLK:{
00518   case S_IFCHR:
00519     // These IOCTLs are standard across the BSD family; Darwin has a different set though.
00520 #if defined(DIOCGMEDIASIZE) && defined(DIOCGSECTORSIZE)
00521       if (ioctl(fd, DIOCGMEDIASIZE, &size) < 0) {
00522         Warning("unable to get disk information for '%s': %s", n, strerror(errno));
00523         err = "unable to get label information";
00524         goto Lfail;
00525       }
00526       if (ioctl(fd, DIOCGSECTORSIZE, &hw_sector_size) < 0) {
00527         Warning("unable to get disk information for '%s': %s", n, strerror(errno));
00528         err = "unable to get label information";
00529         goto Lfail;
00530       }
00531       devnum = s.st_rdev;
00532       break;
00533 #else
00534       Warning("unable to get disk information for '%s': %s", n, strerror(errno));
00535       err = "no raw disk support on this platform";
00536       goto Lfail;
00537 #endif
00538     }
00539   case S_IFDIR:
00540   case S_IFREG:
00541     if (size <= 0 || size > fsize) {
00542       Warning("bad or missing size for '%s': size %" PRId64 " fsize %" PRId64 "", n, (int64_t) size, fsize);
00543       err = "bad or missing size";
00544       goto Lfail;
00545     }
00546     devnum = s.st_dev;
00547     break;
00548 
00549   default:
00550     Warning("unknown file type '%s': %d", n, s.st_mode);
00551     return "unknown file type";
00552     break;
00553   }
00554 
00555   disk_id = devnum;
00556 
00557   pathname = ats_strdup(an);
00558   // igalic: blocks = size / hw_sector_size; was wrong TS-1707
00559   // This code needs refactoring to unify the code-paths which are equal across platforms.
00560   blocks = size / STORE_BLOCK_SIZE;
00561   file_pathname = !((s.st_mode & S_IFMT) == S_IFDIR);
00562 
00563   // This is so FreeBSD admins don't worry about our malicious code creating boot sector viruses:
00564   if (((s.st_mode & S_IFMT) == S_IFBLK) || ((s.st_mode & S_IFMT) == S_IFCHR)) {
00565     blocks--;
00566     offset = 1;
00567   }
00568 
00569   Debug("cache_init", "Span::init - %s hw_sector_size = %d  size = %" PRId64 ", blocks = %" PRId64 ", disk_id = %d, file_pathname = %d", pathname.get(), hw_sector_size, size, blocks, disk_id, file_pathname);
00570 
00571 Lfail:
00572   return err;
00573 }
00574 
00575 #endif
00576 
00577 #if defined(solaris)
00578 
00579 const char *
00580 Span::init(char *filename, int64_t size)
00581 {
00582   int devnum = 0;
00583   const char *err = NULL;
00584   int ret = 0;
00585 
00586   //
00587   // All file types on Solaris can be mmaped
00588   //
00589   is_mmapable_internal = true;
00590 
00591   ats_scoped_fd fd(socketManager.open(filename, O_RDONLY));
00592   if (!fd) {
00593     Warning("unable to open '%s': %s", filename, strerror(errno));
00594     return "unable to open";
00595   }
00596 
00597   // stat the file system
00598   struct stat s;
00599   if ((ret = fstat(fd, &s)) < 0) {
00600     Warning("unable to fstat '%s': %d %d, %s", filename, ret, errno, strerror(errno));
00601     err = "unable to fstat";
00602     goto Lfail;
00603   }
00604 
00605 
00606   switch ((s.st_mode & S_IFMT)) {
00607 
00608   case S_IFBLK:
00609   case S_IFCHR:
00610     devnum = s.st_rdev;
00611     // maybe we should use lseek(fd, 0, SEEK_END) here (it is portable)
00612     size = (int64_t) s.st_size;
00613     hw_sector_size = s.st_blksize;
00614     break;
00615   case S_IFDIR:
00616   case S_IFREG:
00617     int64_t fsize;
00618     struct statvfs fs;
00619     if ((ret = fstatvfs(fd, &fs)) < 0) {
00620       Warning("unable to statvfs '%s': %d %d, %s", filename, ret, errno, strerror(errno));
00621       err = "unable to statvfs";
00622       goto Lfail;
00623     }
00624 
00625     hw_sector_size = fs.f_bsize;
00626     fsize = (int64_t) fs.f_blocks * (int64_t) hw_sector_size;
00627 
00628     if (size <= 0 || size > fsize) {
00629       Warning("bad or missing size for '%s': size %" PRId64 " fsize %" PRId64 "", filename, (int64_t) size, fsize);
00630       err = "bad or missing size";
00631       goto Lfail;
00632     }
00633 
00634     devnum = s.st_dev;
00635     break;
00636 
00637   default:
00638     Warning("unknown file type '%s': %" PRId64 "", filename, (int64_t)(s.st_mode));
00639     err = "unknown file type";
00640     goto Lfail;
00641   }
00642 
00643   // estimate the disk SOLARIS specific
00644   if ((devnum >> 16) == 0x80) {
00645     disk_id = (devnum >> 3) & 0x3F;
00646   } else {
00647     disk_id = devnum;
00648   }
00649 
00650   pathname = ats_strdup(filename);
00651   // is this right Seems like this should be size / hw_sector_size
00652   // igalic: No. See TS-1707
00653   blocks = size / STORE_BLOCK_SIZE;
00654   file_pathname = !((s.st_mode & S_IFMT) == S_IFDIR);
00655 
00656   Debug("cache_init", "Span::init - %s hw_sector_size = %d  size = %" PRId64 ", blocks = %" PRId64 ", disk_id = %d, file_pathname = %d", filename, hw_sector_size, size, blocks, disk_id, file_pathname);
00657 
00658 Lfail:
00659   return err;
00660 }
00661 #endif
00662 
00663 #if defined(linux)
00664 #include <unistd.h>             /* for close() */
00665 #include <sys/ioctl.h>
00666 #include <linux/hdreg.h>        /* for struct hd_geometry */
00667 #include <linux/fs.h>           /* for BLKGETSIZE.  sys/mount.h is another candidate */
00668 
00669 
00670 const char *
00671 Span::init(char *filename, int64_t size)
00672 {
00673   int devnum = 0, arg = 0;
00674   int ret = 0, is_disk = 0;
00675   u_int64_t heads, sectors, cylinders, adjusted_sec;
00676   ats_scoped_fd fd;
00677 
00678   /* Fetch file type */
00679   struct stat stat_buf;
00680   Debug("cache_init", "Span::init(\"%s\",%" PRId64 ")", filename, size);
00681   if ((ret = stat(filename, &stat_buf)) < 0) {
00682     Warning("unable to stat '%s': %d %d, %s", filename, ret, errno, strerror(errno));
00683     return "cannot stat file";
00684   }
00685   switch (stat_buf.st_mode & S_IFMT) {
00686   case S_IFBLK:
00687   case S_IFCHR:
00688     devnum = stat_buf.st_rdev;
00689     Debug("cache_init", "Span::init - %s - devnum = %d",
00690           ((stat_buf.st_mode & S_IFMT) == S_IFBLK) ? "S_IFBLK" : "S_IFCHR", devnum);
00691     break;
00692   case S_IFDIR:
00693     devnum = stat_buf.st_dev;
00694     file_pathname = 0;
00695     Debug("cache_init", "Span::init - S_IFDIR - devnum = %d", devnum);
00696     break;
00697   case S_IFREG:
00698     devnum = stat_buf.st_dev;
00699     file_pathname = 1;
00700     size = stat_buf.st_size;
00701     Debug("cache_init", "Span::init - S_IFREG - devnum = %d", devnum);
00702     break;
00703   default:
00704     break;
00705   }
00706 
00707   fd = socketManager.open(filename, O_RDONLY);
00708   if (!fd) {
00709     Warning("unable to open '%s': %s", filename, strerror(errno));
00710     return "unable to open";
00711   }
00712   Debug("cache_init", "Span::init - socketManager.open(\"%s\", O_RDONLY) = %d", filename, (int)fd);
00713 
00714   adjusted_sec = 1;
00715 #ifdef BLKPBSZGET
00716   if (ioctl(fd, BLKPBSZGET, &arg) == 0)
00717 #else
00718   if (ioctl(fd, BLKSSZGET, &arg) == 0)
00719 #endif
00720   {
00721     hw_sector_size = arg;
00722     is_disk = 1;
00723     adjusted_sec = hw_sector_size / 512;
00724     Debug("cache_init", "Span::init - %s hw_sector_size=%d is_disk=%d adjusted_sec=%" PRId64,
00725           filename, hw_sector_size, is_disk, adjusted_sec);
00726   }
00727 
00728   alignment = 0;
00729 #ifdef BLKALIGNOFF
00730   if (ioctl(fd, BLKALIGNOFF, &arg) == 0) {
00731     alignment = arg;
00732     Debug("cache_init", "Span::init - %s alignment = %d", filename, alignment);
00733   }
00734 #endif
00735 
00736   if (is_disk) {
00737     u_int32_t ioctl_sectors = 0;
00738     u_int64_t ioctl_bytes = 0;
00739     u_int64_t physsectors = 0;
00740 
00741     /* Disks cannot be mmapped */
00742     is_mmapable_internal = false;
00743 
00744     if (!ioctl(fd, BLKGETSIZE64, &ioctl_bytes)) {
00745       heads = 1;
00746       cylinders = 1;
00747       physsectors = ioctl_bytes / hw_sector_size;
00748       sectors = physsectors;
00749     } else if (!ioctl(fd, BLKGETSIZE, &ioctl_sectors)) {
00750       heads = 1;
00751       cylinders = 1;
00752       physsectors = ioctl_sectors;
00753       sectors = physsectors / adjusted_sec;
00754     } else {
00755       struct hd_geometry geometry;
00756       if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
00757         heads = geometry.heads;
00758         sectors = geometry.sectors;
00759         cylinders = geometry.cylinders;
00760         cylinders /= adjusted_sec;      /* do not round up */
00761       } else {
00762         /* Almost certainly something other than a disk device. */
00763         Warning("unable to get geometry '%s': %d %s", filename, errno, strerror(errno));
00764         return ("unable to get geometry");
00765       }
00766     }
00767 
00768     blocks = heads * sectors * cylinders;
00769 
00770     if (size > 0 && blocks * hw_sector_size != size) {
00771       Warning("Warning: you specified a size of %" PRId64 " for %s,\n", size, filename);
00772       Warning("but the device size is %" PRId64 ". Using minimum of the two.\n", (int64_t)blocks * (int64_t)hw_sector_size);
00773       if ((int64_t)blocks * (int64_t)hw_sector_size < size)
00774         size = (int64_t)blocks * (int64_t)hw_sector_size;
00775     } else {
00776       size = (int64_t)blocks * (int64_t)hw_sector_size;
00777     }
00778 
00779     /* I don't know why I'm redefining blocks to be something that is quite
00780      * possibly something other than the actual number of blocks, but the
00781      * code for other arches seems to.  Revisit this, perhaps. */
00782     // igalic: No. See TS-1707
00783     blocks = size / STORE_BLOCK_SIZE;
00784 
00785     Debug("cache_init", "Span::init physical sectors %" PRId64 " total size %" PRId64 " geometry size %" PRId64 " store blocks %" PRId64 "",
00786           physsectors, hw_sector_size * physsectors, size, blocks);
00787 
00788     pathname = ats_strdup(filename);
00789     file_pathname = 1;
00790   } else {
00791     Debug("cache_init", "Span::init - is_disk = %d, raw device = %s", is_disk, (major(devnum) == 162) ? "yes" : "no");
00792     if (major(devnum) == 162) {
00793       /* Oh, a raw device, how cute. */
00794 
00795       if (minor(devnum) == 0)
00796         return "The raw device control file (usually /dev/raw; major 162, minor 0) is not a valid cache location.\n";
00797 
00798       is_mmapable_internal = false;     /* I -think- */
00799       file_pathname = 1;
00800       pathname = ats_strdup(filename);
00801       isRaw = 1;
00802 
00803       if (size <= 0)
00804         return "When using raw devices for cache storage, you must specify a size\n";
00805     } else {
00806       /* Files can be mmapped */
00807       is_mmapable_internal = true;
00808 
00809       /* The code for other arches seems to want to dereference symlinks, but I
00810        * don't particularly understand that behaviour, so I'll just ignore it.
00811        * :) */
00812 
00813       pathname = ats_strdup(filename);
00814       if (!file_pathname)
00815         if (size <= 0)
00816           return "When using directories for cache storage, you must specify a size\n";
00817       Debug("cache_init", "Span::init - mapped file \"%s\", %" PRId64 "", pathname.get(), size);
00818     }
00819     blocks = size / STORE_BLOCK_SIZE;
00820   }
00821 
00822   disk_id = devnum;
00823 
00824   return NULL;
00825 }
00826 #endif
00827 
00828 
00829 
00830 void
00831 Store::normalize()
00832 {
00833   unsigned ndisks = 0;
00834   for (unsigned i = 0; i < n_disks; i++) {
00835     if (disk[i])
00836       disk[ndisks++] = disk[i];
00837   }
00838   n_disks = ndisks;
00839 }
00840 
00841 static unsigned int
00842 try_alloc(Store & target, Span * source, unsigned int start_blocks, bool one_only = false)
00843 {
00844   unsigned int blocks = start_blocks;
00845   Span *ds = NULL;
00846   while (source && blocks) {
00847     if (source->blocks) {
00848       unsigned int a;           // allocated
00849       if (blocks > source->blocks)
00850         a = source->blocks;
00851       else
00852         a = blocks;
00853       Span *d = new Span(*source);
00854 
00855       d->blocks = a;
00856       d->link.next = ds;
00857 
00858       if (d->file_pathname)
00859         source->offset += a;
00860       source->blocks -= a;
00861       ds = d;
00862       blocks -= a;
00863       if (one_only)
00864         break;
00865     }
00866     source = source->link.next;
00867   }
00868   if (ds)
00869     target.add(ds);
00870   return start_blocks - blocks;
00871 }
00872 
00873 void
00874 Store::spread_alloc(Store & s, unsigned int blocks, bool mmapable)
00875 {
00876   //
00877   // Count the eligable disks..
00878   //
00879   int mmapable_disks = 0;
00880   for (unsigned k = 0; k < n_disks; k++) {
00881     if (disk[k]->is_mmapable()) {
00882       mmapable_disks++;
00883     }
00884   }
00885 
00886   int spread_over = n_disks;
00887   if (mmapable) {
00888     spread_over = mmapable_disks;
00889   }
00890 
00891   if (spread_over == 0) {
00892     return;
00893   }
00894 
00895   int disks_left = spread_over;
00896 
00897   for (unsigned i = 0; blocks && disks_left && i < n_disks; i++) {
00898     if (!(mmapable && !disk[i]->is_mmapable())) {
00899       unsigned int target = blocks / disks_left;
00900       if (blocks - target > total_blocks(i + 1))
00901         target = blocks - total_blocks(i + 1);
00902       blocks -= try_alloc(s, disk[i], target);
00903       disks_left--;
00904     }
00905   }
00906 }
00907 
00908 void
00909 Store::try_realloc(Store & s, Store & diff)
00910 {
00911   for (unsigned i = 0; i < s.n_disks; i++) {
00912     Span *prev = 0;
00913     for (Span * sd = s.disk[i]; sd;) {
00914       for (unsigned j = 0; j < n_disks; j++)
00915         for (Span * d = disk[j]; d; d = d->link.next)
00916           if (!strcmp(sd->pathname, d->pathname)) {
00917             if (sd->offset >= d->offset && (sd->end() <= d->end())) {
00918               if (!sd->file_pathname || (sd->end() == d->end())) {
00919                 d->blocks -= sd->blocks;
00920                 goto Lfound;
00921               } else if (sd->offset == d->offset) {
00922                 d->blocks -= sd->blocks;
00923                 d->offset += sd->blocks;
00924                 goto Lfound;
00925               } else {
00926                 Span *x = new Span(*d);
00927                 // d will be the first vol
00928                 d->blocks = sd->offset - d->offset;
00929                 d->link.next = x;
00930                 // x will be the last vol
00931                 x->offset = sd->offset + sd->blocks;
00932                 x->blocks -= x->offset - d->offset;
00933                 goto Lfound;
00934               }
00935             }
00936           }
00937       {
00938         if (!prev)
00939           s.disk[i] = s.disk[i]->link.next;
00940         else
00941           prev->link.next = sd->link.next;
00942         diff.extend(i + 1);
00943         sd->link.next = diff.disk[i];
00944         diff.disk[i] = sd;
00945         sd = prev ? prev->link.next : s.disk[i];
00946         continue;
00947       }
00948     Lfound:;
00949       prev = sd;
00950       sd = sd->link.next;
00951     }
00952   }
00953   normalize();
00954   s.normalize();
00955   diff.normalize();
00956 }
00957 
00958 //
00959 // Stupid grab first availabled space allocator
00960 //
00961 void
00962 Store::alloc(Store & s, unsigned int blocks, bool one_only, bool mmapable)
00963 {
00964   unsigned int oblocks = blocks;
00965   for (unsigned i = 0; blocks && i < n_disks; i++) {
00966     if (!(mmapable && !disk[i]->is_mmapable())) {
00967       blocks -= try_alloc(s, disk[i], blocks, one_only);
00968       if (one_only && oblocks != blocks)
00969         break;
00970     }
00971   }
00972 }
00973 
00974 int
00975 Span::write(int fd)
00976 {
00977   char buf[32];
00978 
00979   if (ink_file_fd_writestring(fd, (pathname ? pathname.get() : ")")) == -1)
00980     return (-1);
00981   if (ink_file_fd_writestring(fd, "\n") == -1)
00982     return (-1);
00983 
00984   snprintf(buf, sizeof(buf), "%" PRId64 "\n", blocks);
00985   if (ink_file_fd_writestring(fd, buf) == -1)
00986     return (-1);
00987 
00988   snprintf(buf, sizeof(buf), "%d\n", file_pathname);
00989   if (ink_file_fd_writestring(fd, buf) == -1)
00990     return (-1);
00991 
00992   snprintf(buf, sizeof(buf), "%" PRId64 "\n", offset);
00993   if (ink_file_fd_writestring(fd, buf) == -1)
00994     return (-1);
00995 
00996   snprintf(buf, sizeof(buf), "%d\n", (int) is_mmapable());
00997   if (ink_file_fd_writestring(fd, buf) == -1)
00998     return (-1);
00999 
01000   return 0;
01001 }
01002 
01003 int
01004 Store::write(int fd, char *name)
01005 {
01006   char buf[32];
01007 
01008   if (ink_file_fd_writestring(fd, name) == -1)
01009     return (-1);
01010   if (ink_file_fd_writestring(fd, "\n") == -1)
01011     return (-1);
01012 
01013   snprintf(buf, sizeof(buf), "%d\n", n_disks);
01014   if (ink_file_fd_writestring(fd, buf) == -1)
01015     return (-1);
01016 
01017   for (unsigned i = 0; i < n_disks; i++) {
01018     int n = 0;
01019     Span *sd = NULL;
01020     for (sd = disk[i]; sd; sd = sd->link.next) {
01021       n++;
01022     }
01023 
01024     snprintf(buf, sizeof(buf), "%d\n", n);
01025     if (ink_file_fd_writestring(fd, buf) == -1)
01026       return (-1);
01027 
01028     for (sd = disk[i]; sd; sd = sd->link.next) {
01029       if (sd->write(fd))
01030         return -1;
01031     }
01032   }
01033   return 0;
01034 }
01035 
01036 int
01037 Span::read(int fd)
01038 {
01039   char buf[PATH_NAME_MAX + 1], p[PATH_NAME_MAX + 1];
01040 
01041   if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
01042     return (-1);
01043   // the above line will guarantee buf to be no longer than PATH_NAME_MAX
01044   // so the next statement should be a safe use of sscanf
01045   // coverity[secure_coding]
01046   if (sscanf(buf, "%s", p) != 1) {
01047     return (-1);
01048   }
01049   pathname = ats_strdup(p);
01050   if (get_int64(fd, blocks) < 0) {
01051     return -1;
01052   }
01053 
01054   int b = 0;
01055   if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
01056     return (-1);
01057   // the above line will guarantee buf to be no longer than PATH_NAME_MAX
01058   // so the next statement should be a safe use of sscanf
01059   // coverity[secure_coding]
01060   if (sscanf(buf, "%d", &b) != 1)
01061     return (-1);
01062   file_pathname = (b ? true : false);
01063 
01064   if (get_int64(fd, offset) < 0) {
01065     return -1;
01066   }
01067 
01068   int tmp;
01069   if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
01070     return (-1);
01071   // the above line will guarantee buf to be no longer than PATH_NAME_MAX
01072   // so the next statement should be a safe use of sscanf
01073   // coverity[secure_coding]
01074   if (sscanf(buf, "%d", &tmp) != 1)
01075     return (-1);
01076   set_mmapable(tmp != 0);
01077 
01078   return (0);
01079 }
01080 
01081 int
01082 Store::read(int fd, char *aname)
01083 {
01084   char *name = aname;
01085   char tname[PATH_NAME_MAX + 1];
01086   char buf[PATH_NAME_MAX + 1];
01087   if (!aname)
01088     name = tname;
01089 
01090   if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
01091     return (-1);
01092   // the above line will guarantee buf to be no longer than PATH_NAME_MAX
01093   // so the next statement should be a safe use of sscanf
01094   // coverity[secure_coding]
01095   if (sscanf(buf, "%s\n", name) != 1)
01096     return (-1);
01097 
01098   if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
01099     return (-1);
01100   // the above line will guarantee buf to be no longer than PATH_NAME_MAX
01101   // so the next statement should be a safe use of sscanf
01102   // coverity[secure_coding]
01103   if (sscanf(buf, "%d\n", &n_disks) != 1)
01104     return (-1);
01105 
01106   disk = (Span **)ats_malloc(sizeof(Span *) * n_disks);
01107   if (!disk)
01108     return -1;
01109   memset(disk, 0, sizeof(Span *) * n_disks);
01110   for (unsigned i = 0; i < n_disks; i++) {
01111     int n = 0;
01112 
01113     if (ink_file_fd_readline(fd, PATH_NAME_MAX, buf) <= 0)
01114       return (-1);
01115     // the above line will guarantee buf to be no longer than PATH_NAME_MAX
01116     // so the next statement should be a safe use of sscanf
01117     // coverity[secure_coding]
01118     if (sscanf(buf, "%d\n", &n) != 1)
01119       return (-1);
01120 
01121     Span *sd = NULL;
01122     while (n--) {
01123       Span *last = sd;
01124       sd = new Span;
01125 
01126       if (!last)
01127         disk[i] = sd;
01128       else
01129         last->link.next = sd;
01130       if (sd->read(fd))
01131         goto Lbail;
01132     }
01133   }
01134   return 0;
01135 Lbail:
01136   for (unsigned i = 0; i < n_disks; i++) {
01137     if (disk[i])
01138       delete disk[i];
01139   }
01140   return -1;
01141 }
01142 
01143 Span *
01144 Span::dup()
01145 {
01146   Span *ds = new Span(*this);
01147   if (this->link.next)
01148     ds->link.next = this->link.next->dup();
01149   return ds;
01150 }
01151 
01152 void
01153 Store::dup(Store & s)
01154 {
01155   s.n_disks = n_disks;
01156   s.disk = (Span **)ats_malloc(sizeof(Span *) * n_disks);
01157   for (unsigned i = 0; i < n_disks; i++) {
01158     s.disk[i] = disk[i]->dup();
01159   }
01160 }
01161 
01162 int
01163 Store::clear(char *filename, bool clear_dirs)
01164 {
01165   char z[STORE_BLOCK_SIZE];
01166   memset(z, 0, STORE_BLOCK_SIZE);
01167   for (unsigned i = 0; i < n_disks; i++) {
01168     Span *ds = disk[i];
01169     for (int j = 0; j < disk[i]->paths(); j++) {
01170       char path[PATH_NAME_MAX + 1];
01171       Span *d = ds->nth(j);
01172       if (!clear_dirs && !d->file_pathname)
01173         continue;
01174       int r = d->path(filename, NULL, path, PATH_NAME_MAX);
01175       if (r < 0)
01176         return -1;
01177       int fd =::open(path, O_RDWR | O_CREAT, 0644);
01178       if (fd < 0)
01179         return -1;
01180       for (int b = 0; d->blocks; b++)
01181         if (socketManager.pwrite(fd, z, STORE_BLOCK_SIZE, d->offset + (b * STORE_BLOCK_SIZE)) < 0) {
01182           close(fd);
01183           return -1;
01184         }
01185       close(fd);
01186     }
01187   }
01188   return 0;
01189 }

Generated by  doxygen 1.7.1