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