00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
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 
00041 Store theStore;
00042 
00043 
00044 
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   
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 
00085 
00086 
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   
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   
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   
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   
00244   
00245   
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   
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   
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     
00306 
00307     ++ln;
00308 
00309     
00310     for ( char *spot = line, *limit = line+len ; spot < limit ; ++spot )
00311       if (ParseRules::is_space(*spot)) *spot = ' '; 
00312 
00313     SimpleTokenizer tokens(line, ' ', SimpleTokenizer::OVERWRITE_INPUT_STRING);
00314 
00315     
00316     path = tokens.getNext();
00317     if (0 == path || '#' == path[0])
00318       continue;
00319 
00320     
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     
00362     if (seed) ns->hash_base_string_set(seed);
00363     if (volume_num > 0) ns->volume_number_set(volume_num);
00364 
00365     
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   
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; 
00386   sort();
00387   ::close(fd);
00388   return NULL;
00389 
00390 Lfail:
00391   
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   
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   
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     
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   
00559   
00560   blocks = size / STORE_BLOCK_SIZE;
00561   file_pathname = !((s.st_mode & S_IFMT) == S_IFDIR);
00562 
00563   
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   
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   
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     
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   
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   
00652   
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>             
00665 #include <sys/ioctl.h>
00666 #include <linux/hdreg.h>        
00667 #include <linux/fs.h>           
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   
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     
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;      
00761       } else {
00762         
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     
00780 
00781 
00782     
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       
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;     
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       
00807       is_mmapable_internal = true;
00808 
00809       
00810 
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;           
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   
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                 
00928                 d->blocks = sd->offset - d->offset;
00929                 d->link.next = x;
00930                 
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 
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   
01044   
01045   
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   
01058   
01059   
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   
01072   
01073   
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   
01093   
01094   
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   
01101   
01102   
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     
01116     
01117     
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 }