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 }