00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
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 
00036 
00037 
00038 
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 
00060 
00061 
00062 
00063 
00064 
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 
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 
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 
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 
00113 
00114 #define OPEN_DIR_BUCKETS           256
00115 
00116 struct EvacuationBlock;
00117 typedef uint32_t DirInfo;
00118 
00119 
00120 
00121 
00122 
00123 
00124 
00125 
00126 
00127 struct Dir
00128 {
00129 #if DO_NOT_REMOVE_THIS
00130   
00131   
00132   
00133   
00134   unsigned int offset:24;       
00135   unsigned int big:2;           
00136   unsigned int size:6;          
00137   unsigned int tag:12;          
00138   unsigned int phase:1;         
00139   unsigned int head:1;          
00140   unsigned int pinned:1;        
00141   unsigned int token:1;         
00142   unsigned int next:16;         
00143   inku16 offset_high;           
00144 #else
00145   uint16_t w[5];
00146   Dir() { dir_clear(this); }
00147 #endif
00148 };
00149 
00150 
00151 
00152 struct FreeDir
00153 {
00154 #if DO_NOT_REMOVE_THIS
00155   
00156   
00157   unsigned int offset:24;       
00158   unsigned int reserved:8;
00159   unsigned int prev:16;         
00160   unsigned int next:16;         
00161 #if TS_USE_INTERIM_CACHE == 1
00162   unsigned int offset_high:12;   
00163   unsigned int index:3;          
00164   unsigned int ininterim:1;          
00165 #else
00166   inku16 offset_high;           
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 
00251 
00252 
00253 
00254 
00255 
00256 LINK_FORWARD_DECLARATION(CacheVC, opendir_link) 
00257 struct OpenDirEntry
00258 {
00259   DLL<CacheVC, Link_CacheVC_opendir_link> writers;       
00260   DLL<CacheVC, Link_CacheVC_opendir_link> readers;         
00261   CacheHTTPInfoVector vector;   
00262                                 
00263                                 
00264   CacheKey single_doc_key;      
00265   Dir single_doc_dir;           
00266   Dir first_dir;                
00267                                 
00268   uint16_t num_writers;           
00269   uint16_t max_writers;           
00270   bool dont_update_directory;   
00271   bool move_resident_alt;       
00272   volatile bool reading_vec;    
00273   volatile bool writing_vec;    
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 
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 
00340 
00341 extern Dir empty_dir;
00342 
00343 
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