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

P_CacheDir.h

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 
00025 #ifndef _P_CACHE_DIR_H__
00026 #define _P_CACHE_DIR_H__
00027 
00028 #include "P_CacheHttp.h"
00029 
00030 struct Vol;
00031 struct InterimCacheVol;
00032 struct CacheVC;
00033 
00034 /*
00035   Directory layout
00036 */
00037 
00038 // Constants
00039 
00040 #define DIR_TAG_WIDTH                   12
00041 #define DIR_MASK_TAG(_t)                ((_t) & ((1 << DIR_TAG_WIDTH) - 1))
00042 #define SIZEOF_DIR                      10
00043 #define ESTIMATED_OBJECT_SIZE           8000
00044 
00045 #define MAX_DIR_SEGMENTS                (32 * (1<<16))
00046 #define DIR_DEPTH                       4
00047 #define DIR_SIZE_WIDTH                  6
00048 #define DIR_BLOCK_SIZES                 4
00049 #define DIR_BLOCK_SHIFT(_i)             (3*(_i))
00050 #define DIR_BLOCK_SIZE(_i)              (CACHE_BLOCK_SIZE << DIR_BLOCK_SHIFT(_i))
00051 #define DIR_SIZE_WITH_BLOCK(_i)         ((1<<DIR_SIZE_WIDTH) * DIR_BLOCK_SIZE(_i))
00052 #define DIR_OFFSET_BITS                 40
00053 #define DIR_OFFSET_MAX                  ((((off_t)1) << DIR_OFFSET_BITS) - 1)
00054 
00055 #define SYNC_MAX_WRITE                  (2 * 1024 * 1024)
00056 #define SYNC_DELAY                      HRTIME_MSECONDS(500)
00057 #define DO_NOT_REMOVE_THIS              0
00058 
00059 // Debugging Options
00060 
00061 //#define DO_CHECK_DIR_FAST
00062 //#define DO_CHECK_DIR
00063 
00064 // Macros
00065 
00066 #ifdef DO_CHECK_DIR
00067 #define CHECK_DIR(_d) ink_assert(check_dir(_d))
00068 #else
00069 #define CHECK_DIR(_d) ((void)0)
00070 #endif
00071 
00072 #define dir_index(_e, _i) ((Dir*)((char*)(_e)->dir + (SIZEOF_DIR * (_i))))
00073 #define dir_assign(_e,_x) do {                \
00074     (_e)->w[0] = (_x)->w[0];                  \
00075     (_e)->w[1] = (_x)->w[1];                  \
00076     (_e)->w[2] = (_x)->w[2];                  \
00077     (_e)->w[3] = (_x)->w[3];                  \
00078     (_e)->w[4] = (_x)->w[4];                  \
00079 } while (0)
00080 #define dir_assign_data(_e,_x) do {           \
00081   unsigned short next = dir_next(_e);         \
00082   dir_assign(_e, _x);                         \
00083   dir_set_next(_e, next);                     \
00084 } while(0)
00085 #if !TS_USE_INTERIM_CACHE
00086 // entry is valid
00087 #define dir_valid(_d, _e)                                               \
00088   (_d->header->phase == dir_phase(_e) ? vol_in_phase_valid(_d, _e) :   \
00089                                         vol_out_of_phase_valid(_d, _e))
00090 // entry is valid and outside of write aggregation region
00091 #define dir_agg_valid(_d, _e)                                            \
00092   (_d->header->phase == dir_phase(_e) ? vol_in_phase_valid(_d, _e) :    \
00093                                         vol_out_of_phase_agg_valid(_d, _e))
00094 // entry may be valid or overwritten in the last aggregated write
00095 #define dir_write_valid(_d, _e)                                         \
00096   (_d->header->phase == dir_phase(_e) ? vol_in_phase_valid(_d, _e) :   \
00097                                         vol_out_of_phase_write_valid(_d, _e))
00098 #define dir_agg_buf_valid(_d, _e)                                          \
00099   (_d->header->phase == dir_phase(_e) && vol_in_phase_agg_buf_valid(_d, _e))
00100 #endif
00101 #define dir_is_empty(_e) (!dir_offset(_e))
00102 #define dir_clear(_e) do { \
00103     (_e)->w[0] = 0; \
00104     (_e)->w[1] = 0; \
00105     (_e)->w[2] = 0; \
00106     (_e)->w[3] = 0; \
00107     (_e)->w[4] = 0; \
00108 } while (0)
00109 #define dir_clean(_e) dir_set_offset(_e,0)
00110 #define dir_segment(_s, _d) vol_dir_segment(_d, _s)
00111 
00112 // OpenDir
00113 
00114 #define OPEN_DIR_BUCKETS           256
00115 
00116 struct EvacuationBlock;
00117 typedef uint32_t DirInfo;
00118 
00119 // Cache Directory
00120 
00121 // INTERNAL: do not access these members directly, use the
00122 // accessors below (e.g. dir_offset, dir_set_offset).
00123 // These structures are stored in memory 2 byte aligned.
00124 // The accessors prevent unaligned memory access which
00125 // is often either less efficient or unsupported depending
00126 // on the processor.
00127 struct Dir
00128 {
00129 #if DO_NOT_REMOVE_THIS
00130   // THE BIT-FIELD INTERPRETATION OF THIS STRUCT WHICH HAS TO 
00131   // USE MACROS TO PREVENT UNALIGNED LOADS
00132   // bits are numbered from lowest in u16 to highest
00133   // always index as u16 to avoid byte order issues
00134   unsigned int offset:24;       // (0,1:0-7) 16M * 512 = 8GB
00135   unsigned int big:2;           // (1:8-9) 512 << (3 * big)
00136   unsigned int size:6;          // (1:10-15) 6**2 = 64, 64*512 = 32768 .. 64*256=16MB
00137   unsigned int tag:12;          // (2:0-11) 2048 / 8 entries/bucket = .4%
00138   unsigned int phase:1;         // (2:12)
00139   unsigned int head:1;          // (2:13) first segment in a document
00140   unsigned int pinned:1;        // (2:14)
00141   unsigned int token:1;         // (2:15)
00142   unsigned int next:16;         // (3)
00143   inku16 offset_high;           // 8GB * 65k = 0.5PB (4)
00144 #else
00145   uint16_t w[5];
00146   Dir() { dir_clear(this); }
00147 #endif
00148 };
00149 
00150 // INTERNAL: do not access these members directly, use the
00151 // accessors below (e.g. dir_offset, dir_set_offset)
00152 struct FreeDir
00153 {
00154 #if DO_NOT_REMOVE_THIS
00155   // THE BIT-FIELD INTERPRETATION OF THIS STRUCT WHICH HAS TO 
00156   // USE MACROS TO PREVENT UNALIGNED LOADS
00157   unsigned int offset:24;       // 0: empty
00158   unsigned int reserved:8;
00159   unsigned int prev:16;         // (2)
00160   unsigned int next:16;         // (3)
00161 #if TS_USE_INTERIM_CACHE == 1
00162   unsigned int offset_high:12;   // 8GB * 4K = 32TB
00163   unsigned int index:3;          // interim index
00164   unsigned int ininterim:1;          // in interim or not
00165 #else
00166   inku16 offset_high;           // 0: empty
00167 #endif
00168 #else
00169   uint16_t w[5];
00170   FreeDir() { dir_clear(this); }
00171 #endif
00172 };
00173 
00174 #if TS_USE_INTERIM_CACHE == 1
00175 #define dir_ininterim(_e) (((_e)->w[4] >> 15) & 1)
00176 #define dir_set_ininterim(_e) ((_e)->w[4] |= (1 << 15));
00177 #define dir_set_indisk(_e) ((_e)->w[4] &= 0x0FFF);
00178 #define dir_get_index(_e) (((_e)->w[4] >> 12) & 0x7)
00179 #define dir_set_index(_e, i) ((_e)->w[4] |= (i << 12))
00180 #define dir_offset(_e) ((int64_t)                \
00181   (((uint64_t)(_e)->w[0]) |           \
00182   (((uint64_t)((_e)->w[1] & 0xFF)) << 16) |       \
00183   (((uint64_t)((_e)->w[4] & 0x0FFF)) << 24)))
00184 #define dir_set_offset(_e, _o) do {            \
00185   (_e)->w[0] = (uint16_t)_o;        \
00186   (_e)->w[1] = (uint16_t)((((_o) >> 16) & 0xFF) | ((_e)->w[1] & 0xFF00));       \
00187   (_e)->w[4] = (((_e)->w[4] & 0xF000) | ((uint16_t)((_o) >> 24)));                                          \
00188 } while (0)
00189 #define dir_get_offset(_e) ((int64_t)                                     \
00190                          (((uint64_t)(_e)->w[0]) |                        \
00191                           (((uint64_t)((_e)->w[1] & 0xFF)) << 16) |       \
00192                           (((uint64_t)(_e)->w[4]) << 24)))
00193 
00194 void clear_interim_dir(Vol *v);
00195 void clear_interimvol_dir(Vol *v, int offset);
00196 void dir_clean_range_interimvol(off_t start, off_t end, InterimCacheVol *svol);
00197 
00198 #else
00199 #define dir_offset(_e) ((int64_t)                                         \
00200                          (((uint64_t)(_e)->w[0]) |                        \
00201                           (((uint64_t)((_e)->w[1] & 0xFF)) << 16) |       \
00202                           (((uint64_t)(_e)->w[4]) << 24)))
00203 #define dir_set_offset(_e,_o) do { \
00204     (_e)->w[0] = (uint16_t)_o;                                                    \
00205     (_e)->w[1] = (uint16_t)((((_o) >> 16) & 0xFF) | ((_e)->w[1] & 0xFF00));       \
00206     (_e)->w[4] = (uint16_t)((_o) >> 24);                                          \
00207 } while (0)
00208 #endif
00209 #define dir_bit(_e, _w, _b) ((uint32_t)(((_e)->w[_w] >> (_b)) & 1))
00210 #define dir_set_bit(_e, _w, _b, _v) (_e)->w[_w] = (uint16_t)(((_e)->w[_w] & ~(1<<(_b))) | (((_v)?1:0)<<(_b)))
00211 #define dir_big(_e) ((uint32_t)((((_e)->w[1]) >> 8)&0x3))
00212 #define dir_set_big(_e, _v) (_e)->w[1] = (uint16_t)(((_e)->w[1] & 0xFCFF) | (((uint16_t)(_v))&0x3)<<8)
00213 #define dir_size(_e) ((uint32_t)(((_e)->w[1]) >> 10))
00214 #define dir_set_size(_e, _v) (_e)->w[1] = (uint16_t)(((_e)->w[1] & ((1<<10)-1)) | ((_v)<<10))
00215 #define dir_set_approx_size(_e, _s) do {                         \
00216   if ((_s) <= DIR_SIZE_WITH_BLOCK(0)) {                          \
00217     dir_set_big(_e,0);                                           \
00218     dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(0));               \
00219   } else if ((_s) <= DIR_SIZE_WITH_BLOCK(1)) {                   \
00220     dir_set_big(_e,1);                                           \
00221     dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(1));               \
00222   } else if ((_s) <= DIR_SIZE_WITH_BLOCK(2)) {                   \
00223     dir_set_big(_e,2);                                           \
00224     dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(2));               \
00225   } else {                                                       \
00226     dir_set_big(_e,3);                                           \
00227     dir_set_size(_e,((_s)-1) / DIR_BLOCK_SIZE(3));               \
00228   }                                                              \
00229 } while (0)
00230 #define dir_approx_size(_e) ((dir_size(_e) + 1) * DIR_BLOCK_SIZE(dir_big(_e)))
00231 #define round_to_approx_dir_size(_s) (_s <= DIR_SIZE_WITH_BLOCK(0) ? ROUND_TO(_s, DIR_BLOCK_SIZE(0)) : \
00232                                       (_s <= DIR_SIZE_WITH_BLOCK(1) ? ROUND_TO(_s, DIR_BLOCK_SIZE(1)) : \
00233                                        (_s <= DIR_SIZE_WITH_BLOCK(2) ? ROUND_TO(_s, DIR_BLOCK_SIZE(2)) : \
00234                                         ROUND_TO(_s, DIR_BLOCK_SIZE(3)))))
00235 #define dir_tag(_e) ((uint32_t)((_e)->w[2]&((1<<DIR_TAG_WIDTH)-1)))
00236 #define dir_set_tag(_e,_t) (_e)->w[2] = (uint16_t)(((_e)->w[2]&~((1<<DIR_TAG_WIDTH)-1)) | ((_t)&((1<<DIR_TAG_WIDTH)-1)))
00237 #define dir_phase(_e) dir_bit(_e,2,12)
00238 #define dir_set_phase(_e,_v) dir_set_bit(_e,2,12,_v)
00239 #define dir_head(_e) dir_bit(_e,2,13)
00240 #define dir_set_head(_e, _v) dir_set_bit(_e,2,13,_v)
00241 #define dir_pinned(_e) dir_bit(_e,2,14)
00242 #define dir_set_pinned(_e, _v) dir_set_bit(_e,2,14,_v)
00243 #define dir_token(_e) dir_bit(_e,2,15)
00244 #define dir_set_token(_e, _v) dir_set_bit(_e,2,15,_v)
00245 #define dir_next(_e) (_e)->w[3]
00246 #define dir_set_next(_e, _o) (_e)->w[3] = (uint16_t)(_o)
00247 #define dir_prev(_e) (_e)->w[2]
00248 #define dir_set_prev(_e,_o) (_e)->w[2] = (uint16_t)(_o)
00249 
00250 // INKqa11166 - Cache can not store 2 HTTP alternates simultaneously.
00251 // To allow this, move the vector from the CacheVC to the OpenDirEntry.
00252 // Each CacheVC now maintains a pointer to this vector. Adding/Deleting
00253 // alternates from this vector is done under the Vol::lock. The alternate
00254 // is deleted/inserted into the vector just before writing the vector disk
00255 // (CacheVC::updateVector).
00256 LINK_FORWARD_DECLARATION(CacheVC, opendir_link) // forward declaration
00257 struct OpenDirEntry
00258 {
00259   DLL<CacheVC, Link_CacheVC_opendir_link> writers;       // list of all the current writers
00260   DLL<CacheVC, Link_CacheVC_opendir_link> readers;         // list of all the current readers - not used
00261   CacheHTTPInfoVector vector;   // Vector for the http document. Each writer
00262                                 // maintains a pointer to this vector and
00263                                 // writes it down to disk.
00264   CacheKey single_doc_key;      // Key for the resident alternate.
00265   Dir single_doc_dir;           // Directory for the resident alternate
00266   Dir first_dir;                // Dir for the vector. If empty, a new dir is
00267                                 // inserted, otherwise this dir is overwritten
00268   uint16_t num_writers;           // num of current writers
00269   uint16_t max_writers;           // max number of simultaneous writers allowed
00270   bool dont_update_directory;   // if set, the first_dir is not updated.
00271   bool move_resident_alt;       // if set, single_doc_dir is inserted.
00272   volatile bool reading_vec;    // somebody is currently reading the vector
00273   volatile bool writing_vec;    // somebody is currently writing the vector
00274 
00275   LINK(OpenDirEntry, link);
00276 
00277   int wait(CacheVC *c, int msec);
00278 
00279   bool has_multiple_writers()
00280   {
00281     return num_writers > 1;
00282   }
00283 };
00284 
00285 struct OpenDir: public Continuation
00286 {
00287   Queue<CacheVC, Link_CacheVC_opendir_link> delayed_readers;
00288   DLL<OpenDirEntry> bucket[OPEN_DIR_BUCKETS];
00289 
00290   int open_write(CacheVC *c, int allow_if_writers, int max_writers);
00291   int close_write(CacheVC *c);
00292   OpenDirEntry *open_read(CryptoHash *key);
00293   int signal_readers(int event, Event *e);
00294 
00295   OpenDir();
00296 };
00297 
00298 struct CacheSync: public Continuation
00299 {
00300   int vol;
00301   char *buf;
00302   size_t buflen;
00303   off_t writepos;
00304   AIOCallbackInternal io;
00305   Event *trigger;
00306   int mainEvent(int event, Event *e);
00307   void aio_write(int fd, char *b, int n, off_t o);
00308 
00309   CacheSync():Continuation(new_ProxyMutex()), vol(0), buf(0), buflen(0), writepos(0), trigger(0)
00310   {
00311     SET_HANDLER(&CacheSync::mainEvent);
00312   }
00313 };
00314 
00315 // Global Functions
00316 
00317 void vol_init_dir(Vol *d);
00318 int dir_token_probe(CacheKey *, Vol *, Dir *);
00319 int dir_probe(CacheKey *, Vol *, Dir *, Dir **);
00320 int dir_insert(CacheKey *key, Vol *d, Dir *to_part);
00321 int dir_overwrite(CacheKey *key, Vol *d, Dir *to_part, Dir *overwrite, bool must_overwrite = true);
00322 int dir_delete(CacheKey *key, Vol *d, Dir *del);
00323 int dir_lookaside_probe(CacheKey *key, Vol *d, Dir *result, EvacuationBlock ** eblock);
00324 int dir_lookaside_insert(EvacuationBlock *b, Vol *d, Dir *to);
00325 int dir_lookaside_fixup(CacheKey *key, Vol *d);
00326 void dir_lookaside_cleanup(Vol *d);
00327 void dir_lookaside_remove(CacheKey *key, Vol *d);
00328 void dir_free_entry(Dir *e, int s, Vol *d);
00329 void dir_sync_init();
00330 int check_dir(Vol *d);
00331 void dir_clean_vol(Vol *d);
00332 void dir_clear_range(off_t start, off_t end, Vol *d);
00333 int dir_segment_accounted(int s, Vol *d, int offby = 0,
00334                           int *free = 0, int *used = 0,
00335                           int *empty = 0, int *valid = 0, int *agg_valid = 0, int *avg_size = 0);
00336 uint64_t dir_entries_used(Vol *d);
00337 void sync_cache_dir_on_shutdown();
00338 
00339 // Global Data
00340 
00341 extern Dir empty_dir;
00342 
00343 // Inline Funtions
00344 
00345 #define dir_in_seg(_s, _i) ((Dir*)(((char*)(_s)) + (SIZEOF_DIR *(_i))))
00346 
00347 TS_INLINE bool
00348 dir_compare_tag(Dir *e, CacheKey *key)
00349 {
00350   return (dir_tag(e) == DIR_MASK_TAG(key->slice32(2)));
00351 }
00352 
00353 TS_INLINE Dir *
00354 dir_from_offset(int64_t i, Dir *seg)
00355 {
00356 #if DIR_DEPTH < 5
00357   if (!i)
00358     return 0;
00359   return dir_in_seg(seg, i);
00360 #else
00361   i = i + ((i - 1) / (DIR_DEPTH - 1));
00362   return dir_in_seg(seg, i);
00363 #endif
00364 }
00365 TS_INLINE Dir *
00366 next_dir(Dir *d, Dir *seg)
00367 {
00368   int i = dir_next(d);
00369   return dir_from_offset(i, seg);
00370 }
00371 TS_INLINE int64_t
00372 dir_to_offset(Dir *d, Dir *seg)
00373 {
00374 #if DIR_DEPTH < 5
00375   return (((char*)d) - ((char*)seg))/SIZEOF_DIR;
00376 #else
00377   int64_t i = (int64_t)((((char*)d) - ((char*)seg))/SIZEOF_DIR);
00378   i = i - (i / DIR_DEPTH);
00379   return i;
00380 #endif
00381 }
00382 TS_INLINE Dir *
00383 dir_bucket(int64_t b, Dir *seg)
00384 {
00385   return dir_in_seg(seg, b * DIR_DEPTH);
00386 }
00387 TS_INLINE Dir *
00388 dir_bucket_row(Dir *b, int64_t i)
00389 {
00390   return dir_in_seg(b, i);
00391 }
00392 
00393 #endif /* _P_CACHE_DIR_H__ */

Generated by  doxygen 1.7.1