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

CacheDisk.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 "P_Cache.h"
00025 
00026 
00027 int
00028 CacheDisk::open(char *s, off_t blocks, off_t askip, int ahw_sector_size, int fildes, bool clear)
00029 {
00030   path = ats_strdup(s);
00031   hw_sector_size = ahw_sector_size;
00032   fd = fildes;
00033   skip = askip;
00034   start = skip;
00035   /* we can't use fractions of store blocks. */
00036   len = blocks;
00037   io.aiocb.aio_fildes = fd;
00038   io.aiocb.aio_reqprio = 0;
00039   io.action = this;
00040   // determine header size and hence start point by successive approximation
00041   uint64_t l;
00042   for (int i = 0; i < 3; i++) {
00043     l = (len * STORE_BLOCK_SIZE) - (start - skip);
00044     if (l >= MIN_VOL_SIZE) {
00045       header_len = sizeof(DiskHeader) + (l / MIN_VOL_SIZE - 1) * sizeof(DiskVolBlock);
00046     } else {
00047       header_len = sizeof(DiskHeader);
00048     }
00049     start = skip + header_len;
00050   }
00051 
00052   disk_vols = (DiskVol **)ats_malloc((l / MIN_VOL_SIZE + 1) * sizeof(DiskVol **));
00053   memset(disk_vols, 0, (l / MIN_VOL_SIZE + 1) * sizeof(DiskVol **));
00054   header_len = ROUND_TO_STORE_BLOCK(header_len);
00055   start = skip + header_len;
00056   num_usable_blocks = (off_t(len * STORE_BLOCK_SIZE) - (start - askip)) >> STORE_BLOCK_SHIFT;
00057 
00058   header = (DiskHeader *)ats_memalign(ats_pagesize(), header_len);
00059   memset(header, 0, header_len);
00060   if (clear) {
00061     SET_HANDLER(&CacheDisk::clearDone);
00062     return clearDisk();
00063   }
00064 
00065   SET_HANDLER(&CacheDisk::openStart);
00066   io.aiocb.aio_offset = skip;
00067   io.aiocb.aio_buf = (char *) header;
00068   io.aiocb.aio_nbytes = header_len;
00069   io.thread = AIO_CALLBACK_THREAD_ANY;
00070   ink_aio_read(&io);
00071   return 0;
00072 }
00073 
00074 CacheDisk::~CacheDisk()
00075 {
00076   if (path) {
00077     ats_free(path);
00078     for (int i = 0; i < (int) header->num_volumes; i++) {
00079       DiskVolBlockQueue *q = NULL;
00080       while (disk_vols[i] && (q = (disk_vols[i]->dpb_queue.pop()))) {
00081         delete q;
00082       }
00083     }
00084     ats_free(disk_vols);
00085     free(header);
00086   }
00087   if (free_blocks) {
00088     DiskVolBlockQueue *q = NULL;
00089     while ((q = (free_blocks->dpb_queue.pop()))) {
00090       delete q;
00091     }
00092     delete free_blocks;
00093   }
00094 }
00095 
00096 int
00097 CacheDisk::clearDisk()
00098 {
00099   delete_all_volumes();
00100 
00101   io.aiocb.aio_offset = skip;
00102   io.aiocb.aio_buf = header;
00103   io.aiocb.aio_nbytes = header_len;
00104   io.thread = AIO_CALLBACK_THREAD_ANY;
00105   ink_aio_write(&io);
00106   return 0;
00107 }
00108 
00109 int
00110 CacheDisk::clearDone(int event, void * /* data ATS_UNUSED */)
00111 {
00112   ink_assert(event == AIO_EVENT_DONE);
00113 
00114   if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
00115     Warning("Could not clear disk header for disk %s: declaring disk bad", path);
00116     SET_DISK_BAD(this);
00117   }
00118 //  update_header();
00119 
00120   SET_HANDLER(&CacheDisk::openDone);
00121   return openDone(EVENT_IMMEDIATE, 0);
00122 }
00123 
00124 int
00125 CacheDisk::openStart(int event, void * /* data ATS_UNUSED */)
00126 {
00127   ink_assert(event == AIO_EVENT_DONE);
00128 
00129   if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
00130     Warning("could not read disk header for disk %s: declaring disk bad", path);
00131     SET_DISK_BAD(this);
00132     SET_HANDLER(&CacheDisk::openDone);
00133     return openDone(EVENT_IMMEDIATE, 0);
00134   }
00135 
00136   if (header->magic != DISK_HEADER_MAGIC || header->num_blocks != static_cast<uint64_t>(len)) {
00137     uint64_t delta_3_2 =  skip - (skip >> STORE_BLOCK_SHIFT); // block count change from 3.2
00138     if (static_cast<uint64_t>(len) == header->num_blocks + delta_3_2) {
00139       header->num_blocks += delta_3_2;
00140       // Only recover the space if there is a single stripe on this disk. The stripe space allocation logic can fail if
00141       // there is any difference at all in splitting the disk into stripes. The problem is we can add only to the last
00142       // stripe, because otherwise the stripe offsets are wrong. But if the stripes didn't split evenly and the last
00143       // stripe isn't the short one, the split will be different this time.
00144       // Further - the size is encoded in to the disk hash so if the size changes, the data is effectively lost anyway.
00145       // So no space recovery.
00146 //      if (header->num_diskvol_blks == 1)
00147 //        header->vol_info[0].len += delta_3_2;
00148     } else {
00149       Warning("disk header different for disk %s: clearing the disk", path);
00150       SET_HANDLER(&CacheDisk::clearDone);
00151       clearDisk();
00152       return EVENT_DONE;
00153     }
00154   }
00155 
00156   cleared = 0;
00157   /* populate disk_vols */
00158   update_header();
00159 
00160   SET_HANDLER(&CacheDisk::openDone);
00161   return openDone(EVENT_IMMEDIATE, 0);
00162 }
00163 
00164 int
00165 CacheDisk::openDone(int /* event ATS_UNUSED */, void * /* data ATS_UNUSED */)
00166 {
00167   if (cacheProcessor.start_done) {
00168     SET_HANDLER(&CacheDisk::syncDone);
00169     cacheProcessor.diskInitialized();
00170     return EVENT_DONE;
00171   } else {
00172     eventProcessor.schedule_in(this, HRTIME_MSECONDS(5), ET_CALL);
00173     return EVENT_CONT;
00174   }
00175 }
00176 
00177 int
00178 CacheDisk::sync()
00179 {
00180   io.aiocb.aio_offset = skip;
00181   io.aiocb.aio_buf = header;
00182   io.aiocb.aio_nbytes = header_len;
00183   io.thread = AIO_CALLBACK_THREAD_ANY;
00184   ink_aio_write(&io);
00185   return 0;
00186 }
00187 
00188 int
00189 CacheDisk::syncDone(int event, void * /* data ATS_UNUSED */)
00190 {
00191   ink_assert(event == AIO_EVENT_DONE);
00192 
00193   if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
00194     Warning("Error writing disk header for disk %s:disk bad", path);
00195     SET_DISK_BAD(this);
00196     return EVENT_DONE;
00197   }
00198 
00199   return EVENT_DONE;
00200 }
00201 
00202 /* size is in store blocks */
00203 DiskVolBlock *
00204 CacheDisk::create_volume(int number, off_t size_in_blocks, int scheme)
00205 {
00206   if (size_in_blocks == 0)
00207     return NULL;
00208 
00209   DiskVolBlockQueue *q = free_blocks->dpb_queue.head;
00210   DiskVolBlockQueue *closest_match = q;
00211 
00212   if (!q)
00213     return NULL;
00214 
00215   off_t max_blocks = MAX_VOL_SIZE >> STORE_BLOCK_SHIFT;
00216   size_in_blocks = (size_in_blocks <= max_blocks) ? size_in_blocks : max_blocks;
00217 
00218   int blocks_per_vol = VOL_BLOCK_SIZE / STORE_BLOCK_SIZE;
00219 //  ink_assert(!(size_in_blocks % blocks_per_vol));
00220   DiskVolBlock *p = 0;
00221   for (; q; q = q->link.next) {
00222     if ((off_t)q->b->len >= size_in_blocks) {
00223       p = q->b;
00224       q->new_block = 1;
00225       break;
00226     } else {
00227       if (closest_match->b->len < q->b->len)
00228         closest_match = q;
00229     }
00230   }
00231 
00232   if (!p && !closest_match)
00233     return NULL;
00234 
00235   if (!p && closest_match) {
00236     /* allocate from the closest match */
00237     q = closest_match;
00238     p = q->b;
00239     q->new_block = 1;
00240     ink_assert(size_in_blocks > (off_t) p->len);
00241     /* allocate in 128 megabyte chunks. The Remaining space should
00242        be thrown away */
00243     size_in_blocks = (p->len - (p->len % blocks_per_vol));
00244     wasted_space += p->len % blocks_per_vol;
00245   }
00246 
00247   free_blocks->dpb_queue.remove(q);
00248   free_space -= p->len;
00249   free_blocks->size -= p->len;
00250 
00251   size_t new_size = p->len - size_in_blocks;
00252   if (new_size >= (size_t)blocks_per_vol) {
00253     /* create a new volume */
00254     DiskVolBlock *dpb = &header->vol_info[header->num_diskvol_blks];
00255     *dpb = *p;
00256     dpb->len -= size_in_blocks;
00257     dpb->offset += ((off_t) size_in_blocks * STORE_BLOCK_SIZE);
00258 
00259     DiskVolBlockQueue *new_q = new DiskVolBlockQueue();
00260     new_q->b = dpb;
00261     free_blocks->dpb_queue.enqueue(new_q);
00262     free_blocks->size += dpb->len;
00263     free_space += dpb->len;
00264     header->num_diskvol_blks++;
00265   } else
00266     header->num_free--;
00267 
00268   p->len = size_in_blocks;
00269   p->free = 0;
00270   p->number = number;
00271   p->type = scheme;
00272   header->num_used++;
00273 
00274   unsigned int i;
00275   /* add it to its disk_vol */
00276   for (i = 0; i < header->num_volumes; i++) {
00277     if (disk_vols[i]->vol_number == number) {
00278       disk_vols[i]->dpb_queue.enqueue(q);
00279       disk_vols[i]->num_volblocks++;
00280       disk_vols[i]->size += q->b->len;
00281       break;
00282     }
00283   }
00284   if (i == header->num_volumes) {
00285     disk_vols[i] = new DiskVol();
00286     disk_vols[i]->num_volblocks = 1;
00287     disk_vols[i]->vol_number = number;
00288     disk_vols[i]->disk = this;
00289     disk_vols[i]->dpb_queue.enqueue(q);
00290     disk_vols[i]->size = q->b->len;
00291     header->num_volumes++;
00292   }
00293   return p;
00294 }
00295 
00296 
00297 int
00298 CacheDisk::delete_volume(int number)
00299 {
00300   unsigned int i;
00301   for (i = 0; i < header->num_volumes; i++) {
00302     if (disk_vols[i]->vol_number == number) {
00303 
00304       DiskVolBlockQueue *q;
00305       for (q = disk_vols[i]->dpb_queue.head; q;) {
00306         DiskVolBlock *p = q->b;
00307         p->type = CACHE_NONE_TYPE;
00308         p->free = 1;
00309         free_space += p->len;
00310         header->num_free++;
00311         header->num_used--;
00312         DiskVolBlockQueue *temp_q = q->link.next;
00313         disk_vols[i]->dpb_queue.remove(q);
00314         free_blocks->dpb_queue.enqueue(q);
00315         q = temp_q;
00316       }
00317       free_blocks->num_volblocks += disk_vols[i]->num_volblocks;
00318       free_blocks->size += disk_vols[i]->size;
00319 
00320       delete disk_vols[i];
00321       /* move all the other disk vols */
00322       for (unsigned int j = i; j < (header->num_volumes - 1); j++) {
00323         disk_vols[j] = disk_vols[j + 1];
00324       }
00325       header->num_volumes--;
00326       return 0;
00327     }
00328   }
00329   return -1;
00330 }
00331 
00332 void
00333 CacheDisk::update_header()
00334 {
00335   unsigned int n = 0;
00336   unsigned int i, j;
00337   if (free_blocks) {
00338     DiskVolBlockQueue *q = NULL;
00339     while ((q = (free_blocks->dpb_queue.pop()))) {
00340       delete q;
00341     }
00342     delete free_blocks;
00343   }
00344   free_blocks = new DiskVol();
00345   free_blocks->vol_number = -1;
00346   free_blocks->disk = this;
00347   free_blocks->num_volblocks = 0;
00348   free_blocks->size = 0;
00349   free_space = 0;
00350 
00351   for (i = 0; i < header->num_diskvol_blks; i++) {
00352     DiskVolBlockQueue *dpbq = new DiskVolBlockQueue();
00353     bool dpbq_referenced = false;
00354     dpbq->b = &header->vol_info[i];
00355     if (header->vol_info[i].free) {
00356       free_blocks->num_volblocks++;
00357       free_blocks->size += dpbq->b->len;
00358       free_blocks->dpb_queue.enqueue(dpbq);
00359       free_space += dpbq->b->len;
00360       continue;
00361     }
00362     int vol_number = header->vol_info[i].number;
00363     for (j = 0; j < n; j++) {
00364       if (disk_vols[j]->vol_number == vol_number) {
00365         disk_vols[j]->dpb_queue.enqueue(dpbq);
00366         dpbq_referenced = true;
00367         disk_vols[j]->num_volblocks++;
00368         disk_vols[j]->size += dpbq->b->len;
00369         break;
00370       }
00371     }
00372     if (j == n) {
00373       // did not find a matching volume number. create a new
00374       // one
00375       disk_vols[j] = new DiskVol();
00376       disk_vols[j]->vol_number = vol_number;
00377       disk_vols[j]->disk = this;
00378       disk_vols[j]->num_volblocks = 1;
00379       disk_vols[j]->size = dpbq->b->len;
00380       disk_vols[j]->dpb_queue.enqueue(dpbq);
00381       dpbq_referenced = true;
00382       n++;
00383     }
00384     // check to see if we even used the dpbq allocated
00385     if (dpbq_referenced == false) {
00386       delete dpbq;
00387     }
00388   }
00389 
00390   ink_assert(n == header->num_volumes);
00391 }
00392 
00393 DiskVol *
00394 CacheDisk::get_diskvol(int vol_number)
00395 {
00396   unsigned int i;
00397   for (i = 0; i < header->num_volumes; i++) {
00398     if (disk_vols[i]->vol_number == vol_number) {
00399       return disk_vols[i];
00400     }
00401   }
00402   return NULL;
00403 }
00404 
00405 int
00406 CacheDisk::delete_all_volumes()
00407 {
00408   header->vol_info[0].offset = start;
00409   header->vol_info[0].len = num_usable_blocks;
00410   header->vol_info[0].type = CACHE_NONE_TYPE;
00411   header->vol_info[0].free = 1;
00412 
00413   header->magic = DISK_HEADER_MAGIC;
00414   header->num_used = 0;
00415   header->num_volumes = 0;
00416   header->num_free = 1;
00417   header->num_diskvol_blks = 1;
00418   header->num_blocks = len;
00419   cleared = 1;
00420   update_header();
00421 
00422   return 0;
00423 }

Generated by  doxygen 1.7.1