Go to the documentation of this file.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 "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   
00036   len = blocks;
00037   io.aiocb.aio_fildes = fd;
00038   io.aiocb.aio_reqprio = 0;
00039   io.action = this;
00040   
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 * )
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 
00119 
00120   SET_HANDLER(&CacheDisk::openDone);
00121   return openDone(EVENT_IMMEDIATE, 0);
00122 }
00123 
00124 int
00125 CacheDisk::openStart(int event, void * )
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); 
00138     if (static_cast<uint64_t>(len) == header->num_blocks + delta_3_2) {
00139       header->num_blocks += delta_3_2;
00140       
00141       
00142       
00143       
00144       
00145       
00146 
00147 
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   
00158   update_header();
00159 
00160   SET_HANDLER(&CacheDisk::openDone);
00161   return openDone(EVENT_IMMEDIATE, 0);
00162 }
00163 
00164 int
00165 CacheDisk::openDone(int , void * )
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 * )
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 
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 
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     
00237     q = closest_match;
00238     p = q->b;
00239     q->new_block = 1;
00240     ink_assert(size_in_blocks > (off_t) p->len);
00241     
00242 
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     
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   
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       
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       
00374       
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     
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 }