~ps10gel/ubuntu/xenial/trafficserver/6.2.0

« back to all changes in this revision

Viewing changes to iocore/cache/CacheDisk.cc

  • Committer: Bazaar Package Importer
  • Author(s): Arno Toell
  • Date: 2011-01-13 11:49:18 UTC
  • Revision ID: james.westby@ubuntu.com-20110113114918-vu422h8dknrgkj15
Tags: upstream-2.1.5-unstable
ImportĀ upstreamĀ versionĀ 2.1.5-unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 
 
3
  A brief file description
 
4
 
 
5
  @section license License
 
6
 
 
7
  Licensed to the Apache Software Foundation (ASF) under one
 
8
  or more contributor license agreements.  See the NOTICE file
 
9
  distributed with this work for additional information
 
10
  regarding copyright ownership.  The ASF licenses this file
 
11
  to you under the Apache License, Version 2.0 (the
 
12
  "License"); you may not use this file except in compliance
 
13
  with the License.  You may obtain a copy of the License at
 
14
 
 
15
      http://www.apache.org/licenses/LICENSE-2.0
 
16
 
 
17
  Unless required by applicable law or agreed to in writing, software
 
18
  distributed under the License is distributed on an "AS IS" BASIS,
 
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
20
  See the License for the specific language governing permissions and
 
21
  limitations under the License.
 
22
 */
 
23
 
 
24
#include "P_Cache.h"
 
25
 
 
26
 
 
27
int
 
28
CacheDisk::open(char *s, off_t blocks, off_t askip, int ahw_sector_size, int fildes, bool clear)
 
29
{
 
30
  path = xstrdup(s);
 
31
  hw_sector_size = ahw_sector_size;
 
32
  fd = fildes;
 
33
  skip = askip;
 
34
  start = skip;
 
35
  /* we can't use fractions of store blocks. */
 
36
  len = blocks;
 
37
  io.aiocb.aio_fildes = fd;
 
38
  io.aiocb.aio_reqprio = 0;
 
39
  io.action = this;
 
40
  // determine header size and hence start point by successive approximation
 
41
  uint64_t l;
 
42
  for (int i = 0; i < 3; i++) {
 
43
    l = (len * STORE_BLOCK_SIZE) - (start - skip);
 
44
    if (l >= MIN_PART_SIZE) {
 
45
      header_len = sizeof(DiskHeader) + (l / MIN_PART_SIZE - 1) * sizeof(DiskPartBlock);
 
46
    } else {
 
47
      header_len = sizeof(DiskHeader);
 
48
    }
 
49
    start = skip + header_len;
 
50
  }
 
51
 
 
52
  disk_parts = (DiskPart **) xmalloc((l / MIN_PART_SIZE + 1) * sizeof(DiskPart **));
 
53
  memset(disk_parts, 0, (l / MIN_PART_SIZE + 1) * sizeof(DiskPart **));
 
54
  header_len = ROUND_TO_STORE_BLOCK(header_len);
 
55
  start = skip + header_len;
 
56
  num_usable_blocks = (off_t(len * STORE_BLOCK_SIZE) - (start - askip)) >> STORE_BLOCK_SHIFT;
 
57
 
 
58
#if defined(_WIN32)
 
59
  header = (DiskHeader *) malloc(header_len);
 
60
#else
 
61
  header = (DiskHeader *) valloc(header_len);
 
62
#endif
 
63
 
 
64
  memset(header, 0, header_len);
 
65
  if (clear) {
 
66
    SET_HANDLER(&CacheDisk::clearDone);
 
67
    return clearDisk();
 
68
  }
 
69
 
 
70
  SET_HANDLER(&CacheDisk::openStart);
 
71
  io.aiocb.aio_offset = skip;
 
72
  io.aiocb.aio_buf = (char *) header;
 
73
  io.aiocb.aio_nbytes = header_len;
 
74
  io.thread = AIO_CALLBACK_THREAD_ANY;
 
75
  ink_aio_read(&io);
 
76
  return 0;
 
77
}
 
78
 
 
79
CacheDisk::~CacheDisk()
 
80
{
 
81
  if (path) {
 
82
    xfree(path);
 
83
    for (int i = 0; i < (int) header->num_partitions; i++) {
 
84
      DiskPartBlockQueue *q = NULL;
 
85
      while (disk_parts[i] && (q = (disk_parts[i]->dpb_queue.pop()))) {
 
86
        delete q;
 
87
      }
 
88
    }
 
89
    xfree(disk_parts);
 
90
    free(header);
 
91
  }
 
92
  if (free_blocks) {
 
93
    DiskPartBlockQueue *q = NULL;
 
94
    while ((q = (free_blocks->dpb_queue.pop()))) {
 
95
      delete q;
 
96
    }
 
97
    delete free_blocks;
 
98
  }
 
99
}
 
100
 
 
101
int
 
102
CacheDisk::clearDisk()
 
103
{
 
104
  delete_all_partitions();
 
105
 
 
106
  io.aiocb.aio_offset = skip;
 
107
  io.aiocb.aio_buf = header;
 
108
  io.aiocb.aio_nbytes = header_len;
 
109
  io.thread = AIO_CALLBACK_THREAD_ANY;
 
110
  ink_aio_write(&io);
 
111
  return 0;
 
112
}
 
113
 
 
114
int
 
115
CacheDisk::clearDone(int event, void *data)
 
116
{
 
117
  NOWARN_UNUSED(data);
 
118
  ink_assert(event == AIO_EVENT_DONE);
 
119
 
 
120
  if ((int) io.aiocb.aio_nbytes != (int) io.aio_result) {
 
121
    Warning("Could not clear disk header for disk %s: declaring disk bad", path);
 
122
    SET_DISK_BAD(this);
 
123
  }
 
124
//  update_header();
 
125
 
 
126
  SET_HANDLER(&CacheDisk::openDone);
 
127
  return openDone(EVENT_IMMEDIATE, 0);
 
128
}
 
129
 
 
130
int
 
131
CacheDisk::openStart(int event, void *data)
 
132
{
 
133
  NOWARN_UNUSED(data);
 
134
  ink_assert(event == AIO_EVENT_DONE);
 
135
 
 
136
  if ((int) io.aiocb.aio_nbytes != (int) io.aio_result) {
 
137
    Warning("could not read disk header for disk %s: declaring disk bad", path);
 
138
    SET_DISK_BAD(this);
 
139
    SET_HANDLER(&CacheDisk::openDone);
 
140
    return openDone(EVENT_IMMEDIATE, 0);
 
141
  }
 
142
 
 
143
  if (header->magic != DISK_HEADER_MAGIC || header->num_blocks != len) {
 
144
    Warning("disk header different for disk %s: clearing the disk", path);
 
145
    SET_HANDLER(&CacheDisk::clearDone);
 
146
    clearDisk();
 
147
    return EVENT_DONE;
 
148
  }
 
149
 
 
150
  cleared = 0;
 
151
  /* populate disk_parts */
 
152
  update_header();
 
153
 
 
154
  SET_HANDLER(&CacheDisk::openDone);
 
155
  return openDone(EVENT_IMMEDIATE, 0);
 
156
}
 
157
 
 
158
int
 
159
CacheDisk::openDone(int event, void *data)
 
160
{
 
161
  NOWARN_UNUSED(data);
 
162
  NOWARN_UNUSED(event);
 
163
  if (cacheProcessor.start_done) {
 
164
    SET_HANDLER(&CacheDisk::syncDone);
 
165
    cacheProcessor.diskInitialized();
 
166
    return EVENT_DONE;
 
167
  } else {
 
168
    eventProcessor.schedule_in(this, HRTIME_MSECONDS(5), ET_CALL);
 
169
    return EVENT_CONT;
 
170
  }
 
171
}
 
172
 
 
173
int
 
174
CacheDisk::sync()
 
175
{
 
176
  io.aiocb.aio_offset = skip;
 
177
  io.aiocb.aio_buf = header;
 
178
  io.aiocb.aio_nbytes = header_len;
 
179
  io.thread = AIO_CALLBACK_THREAD_ANY;
 
180
  ink_aio_write(&io);
 
181
  return 0;
 
182
}
 
183
 
 
184
int
 
185
CacheDisk::syncDone(int event, void *data)
 
186
{
 
187
  NOWARN_UNUSED(data);
 
188
 
 
189
  ink_assert(event == AIO_EVENT_DONE);
 
190
 
 
191
  if ((int) io.aiocb.aio_nbytes != (int) io.aio_result) {
 
192
    Warning("Error writing disk header for disk %s:disk bad", path);
 
193
    SET_DISK_BAD(this);
 
194
    return EVENT_DONE;
 
195
  }
 
196
 
 
197
  return EVENT_DONE;
 
198
}
 
199
 
 
200
/* size is in store blocks */
 
201
DiskPartBlock *
 
202
CacheDisk::create_partition(int number, off_t size_in_blocks, int scheme)
 
203
{
 
204
  if (size_in_blocks == 0)
 
205
    return NULL;
 
206
 
 
207
  DiskPartBlockQueue *q = free_blocks->dpb_queue.head;
 
208
  DiskPartBlockQueue *closest_match = q;
 
209
 
 
210
  if (!q)
 
211
    return NULL;
 
212
  off_t max_blocks = MAX_PART_SIZE >> STORE_BLOCK_SHIFT;
 
213
  size_in_blocks = (size_in_blocks <= max_blocks) ? size_in_blocks : max_blocks;
 
214
 
 
215
  int blocks_per_part = PART_BLOCK_SIZE / STORE_BLOCK_SIZE;
 
216
//  ink_assert(!(size_in_blocks % blocks_per_part));
 
217
  DiskPartBlock *p = 0;
 
218
  for (; q; q = q->link.next) {
 
219
    if (q->b->len >= (unsigned int) size_in_blocks) {
 
220
      p = q->b;
 
221
      q->new_block = 1;
 
222
      break;
 
223
    } else {
 
224
      if (closest_match->b->len < q->b->len)
 
225
        closest_match = q;
 
226
    }
 
227
  }
 
228
 
 
229
  if (!p && !closest_match)
 
230
    return NULL;
 
231
 
 
232
  if (!p && closest_match) {
 
233
    /* allocate from the closest match */
 
234
    q = closest_match;
 
235
    p = q->b;
 
236
    q->new_block = 1;
 
237
    ink_assert(size_in_blocks > (int) p->len);
 
238
    /* allocate in 128 megabyte chunks. The Remaining space should
 
239
       be thrown away */
 
240
    size_in_blocks = (p->len - (p->len % blocks_per_part));
 
241
    wasted_space += p->len % blocks_per_part;
 
242
  }
 
243
 
 
244
  free_blocks->dpb_queue.remove(q);
 
245
  free_space -= p->len;
 
246
  free_blocks->size -= p->len;
 
247
 
 
248
  int new_size = p->len - size_in_blocks;
 
249
  if (new_size >= blocks_per_part) {
 
250
    /* create a new partition */
 
251
    DiskPartBlock *dpb = &header->part_info[header->num_diskpart_blks];
 
252
    *dpb = *p;
 
253
    dpb->len -= size_in_blocks;
 
254
    dpb->offset += ((off_t) size_in_blocks * STORE_BLOCK_SIZE);
 
255
 
 
256
    DiskPartBlockQueue *new_q = NEW(new DiskPartBlockQueue());
 
257
    new_q->b = dpb;
 
258
    free_blocks->dpb_queue.enqueue(new_q);
 
259
    free_blocks->size += dpb->len;
 
260
    free_space += dpb->len;
 
261
    header->num_diskpart_blks++;
 
262
  } else
 
263
    header->num_free--;
 
264
 
 
265
  p->len = size_in_blocks;
 
266
  p->free = 0;
 
267
  p->number = number;
 
268
  p->type = scheme;
 
269
  header->num_used++;
 
270
 
 
271
  unsigned int i;
 
272
  /* add it to its disk_part */
 
273
  for (i = 0; i < header->num_partitions; i++) {
 
274
    if (disk_parts[i]->part_number == number) {
 
275
      disk_parts[i]->dpb_queue.enqueue(q);
 
276
      disk_parts[i]->num_partblocks++;
 
277
      disk_parts[i]->size += q->b->len;
 
278
      break;
 
279
    }
 
280
  }
 
281
  if (i == header->num_partitions) {
 
282
    disk_parts[i] = NEW(new DiskPart());
 
283
    disk_parts[i]->num_partblocks = 1;
 
284
    disk_parts[i]->part_number = number;
 
285
    disk_parts[i]->disk = this;
 
286
    disk_parts[i]->dpb_queue.enqueue(q);
 
287
    disk_parts[i]->size = q->b->len;
 
288
    header->num_partitions++;
 
289
  }
 
290
  return p;
 
291
}
 
292
 
 
293
 
 
294
int
 
295
CacheDisk::delete_partition(int number)
 
296
{
 
297
  unsigned int i;
 
298
  for (i = 0; i < header->num_partitions; i++) {
 
299
    if (disk_parts[i]->part_number == number) {
 
300
 
 
301
      DiskPartBlockQueue *q;
 
302
      for (q = disk_parts[i]->dpb_queue.head; q;) {
 
303
        DiskPartBlock *p = q->b;
 
304
        p->type = CACHE_NONE_TYPE;
 
305
        p->free = 1;
 
306
        free_space += p->len;
 
307
        header->num_free++;
 
308
        header->num_used--;
 
309
        DiskPartBlockQueue *temp_q = q->link.next;
 
310
        disk_parts[i]->dpb_queue.remove(q);
 
311
        free_blocks->dpb_queue.enqueue(q);
 
312
        q = temp_q;
 
313
      }
 
314
      free_blocks->num_partblocks += disk_parts[i]->num_partblocks;
 
315
      free_blocks->size += disk_parts[i]->size;
 
316
 
 
317
      delete disk_parts[i];
 
318
      /* move all the other disk parts */
 
319
      for (unsigned int j = i; j < (header->num_partitions - 1); j++) {
 
320
        disk_parts[j] = disk_parts[j + 1];
 
321
      }
 
322
      header->num_partitions--;
 
323
      return 0;
 
324
    }
 
325
  }
 
326
  return -1;
 
327
}
 
328
 
 
329
void
 
330
CacheDisk::update_header()
 
331
{
 
332
  unsigned int n = 0;
 
333
  unsigned int i, j;
 
334
  if (free_blocks) {
 
335
    DiskPartBlockQueue *q = NULL;
 
336
    while ((q = (free_blocks->dpb_queue.pop()))) {
 
337
      delete q;
 
338
    }
 
339
    delete free_blocks;
 
340
  }
 
341
  free_blocks = NEW(new DiskPart());
 
342
  free_blocks->part_number = -1;
 
343
  free_blocks->disk = this;
 
344
  free_blocks->num_partblocks = 0;
 
345
  free_blocks->size = 0;
 
346
  free_space = 0;
 
347
 
 
348
  for (i = 0; i < header->num_diskpart_blks; i++) {
 
349
    DiskPartBlockQueue *dpbq = NEW(new DiskPartBlockQueue());
 
350
    bool dpbq_referenced = false;
 
351
    dpbq->b = &header->part_info[i];
 
352
    if (header->part_info[i].free) {
 
353
      free_blocks->num_partblocks++;
 
354
      free_blocks->size += dpbq->b->len;
 
355
      free_blocks->dpb_queue.enqueue(dpbq);
 
356
      dpbq_referenced = true;
 
357
      free_space += dpbq->b->len;
 
358
      continue;
 
359
    }
 
360
    int part_number = header->part_info[i].number;
 
361
    for (j = 0; j < n; j++) {
 
362
      if (disk_parts[j]->part_number == part_number) {
 
363
        disk_parts[j]->dpb_queue.enqueue(dpbq);
 
364
        dpbq_referenced = true;
 
365
        disk_parts[j]->num_partblocks++;
 
366
        disk_parts[j]->size += dpbq->b->len;
 
367
        break;
 
368
      }
 
369
    }
 
370
    if (j == n) {
 
371
      // did not find a matching partition number. create a new
 
372
      // one
 
373
      disk_parts[j] = NEW(new DiskPart());
 
374
      disk_parts[j]->part_number = part_number;
 
375
      disk_parts[j]->disk = this;
 
376
      disk_parts[j]->num_partblocks = 1;
 
377
      disk_parts[j]->size = dpbq->b->len;
 
378
      disk_parts[j]->dpb_queue.enqueue(dpbq);
 
379
      dpbq_referenced = true;
 
380
      n++;
 
381
    }
 
382
    // check to see if we even used the dpbq allocated
 
383
    if (dpbq_referenced == false) {
 
384
      delete dpbq;
 
385
    }
 
386
  }
 
387
 
 
388
  ink_assert(n == header->num_partitions);
 
389
}
 
390
 
 
391
DiskPart *
 
392
CacheDisk::get_diskpart(int part_number)
 
393
{
 
394
  unsigned int i;
 
395
  for (i = 0; i < header->num_partitions; i++) {
 
396
    if (disk_parts[i]->part_number == part_number) {
 
397
      return disk_parts[i];
 
398
    }
 
399
  }
 
400
  return NULL;
 
401
}
 
402
 
 
403
int
 
404
CacheDisk::delete_all_partitions()
 
405
{
 
406
  header->part_info[0].offset = start;
 
407
  header->part_info[0].len = num_usable_blocks;
 
408
  header->part_info[0].type = CACHE_NONE_TYPE;
 
409
  header->part_info[0].free = 1;
 
410
 
 
411
  header->magic = DISK_HEADER_MAGIC;
 
412
  header->num_used = 0;
 
413
  header->num_partitions = 0;
 
414
  header->num_free = 1;
 
415
  header->num_diskpart_blks = 1;
 
416
  header->num_blocks = len;
 
417
  cleared = 1;
 
418
  update_header();
 
419
 
 
420
  return 0;
 
421
}