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 }