1
+ #include "cache.h"
2
+
3
+ #include "csapp.h"
4
+
5
+ const int block_size [6 ] = {1024 , 5120 , 10240 , 20480 , 51200 , 102400 };
6
+ const int block_cnt [6 ] = {24 , 10 , 8 , 6 , 5 , 5 };
7
+
8
+ cache_block * cache_lists [LIST_CNT ];
9
+
10
+ void cache_init () {
11
+ for (int i = 0 ; i < LIST_CNT ; ++ i ) {
12
+ /* initialize cache block list */
13
+ cache_lists [i ] =
14
+ (cache_block * )malloc (block_cnt [i ] * sizeof (cache_block ));
15
+ cache_block * this_list = cache_lists [i ];
16
+ /* initialize every block in this list */
17
+ for (int j = 0 ; j < block_cnt [i ]; ++ j ) {
18
+ this_list [j ].url = (char * )calloc (MAXLINE , sizeof (char ));
19
+ this_list [j ].data = (char * )calloc (block_size [i ], sizeof (char ));
20
+ this_list [j ].datasize = 0 ;
21
+ this_list [j ].timestamp = 0 ;
22
+ pthread_rwlock_init (& this_list [j ].rwlock , NULL );
23
+ }
24
+ }
25
+ }
26
+
27
+ void cache_deinit () {
28
+ for (int i = 0 ; i < LIST_CNT ; ++ i ) {
29
+ cache_block * this_list = cache_lists [i ];
30
+ for (int j = 0 ; j < block_cnt [j ]; ++ j ) {
31
+ free (this_list [j ].url );
32
+ free (this_list [j ].data );
33
+ pthread_rwlock_destroy (& this_list [j ].rwlock );
34
+ }
35
+ free (this_list );
36
+ }
37
+ }
38
+
39
+ int cache_read (char * url , int fd ) {
40
+ /* search every list */
41
+ int cache_hit = 0 ;
42
+ cache_block * target = NULL ;
43
+ for (int i = 0 ; i < LIST_CNT ; ++ i ) {
44
+ cache_block * this_list = cache_lists [i ];
45
+ /* search every block in this list */
46
+ for (int j = 0 ; j < block_cnt [i ]; ++ j ) {
47
+ /* if uri match, and timestamp not zero(means block valid), then
48
+ * hit! */
49
+ if (!strcmp (url , this_list [j ].url ) && this_list [j ].timestamp ) {
50
+ cache_hit = 1 ;
51
+ target = & this_list [j ];
52
+ break ;
53
+ }
54
+ }
55
+ if (cache_hit ) break ;
56
+ }
57
+ if (!cache_hit ) {
58
+ printf ("no matched cache block\n" );
59
+ return 0 ;
60
+ }
61
+
62
+ /* first update timestamp before block kicked by other thread */
63
+ pthread_rwlock_wrlock (& target -> rwlock );
64
+ /* we have to check target block again incase other thread kiked it */
65
+ if (strcmp (url , target -> url )) {
66
+ printf ("oops, the matched block modified by other thread just now\n" );
67
+ pthread_rwlock_unlock (& target -> rwlock );
68
+ return 0 ;
69
+ }
70
+ /* we can update the timestamp safely */
71
+ target -> timestamp = get_timestamp ();
72
+ pthread_rwlock_unlock (& target -> rwlock );
73
+
74
+ /* now we can get cache content */
75
+ pthread_rwlock_rdlock (& target -> rwlock );
76
+ /* double check, just in case */
77
+ if (strcmp (url , target -> url )) {
78
+ printf ("oops, the matched block modified by other thread just now\n" );
79
+ pthread_rwlock_unlock (& target -> rwlock );
80
+ return 0 ;
81
+ }
82
+ Rio_writen (fd , target -> data , target -> datasize );
83
+ pthread_rwlock_unlock (& target -> rwlock );
84
+ printf ("fetch content from cache\n" );
85
+ return 1 ;
86
+ }
87
+
88
+ void cache_write (char * url , char * data , int len ) {
89
+ int list_idx = 0 ;
90
+ cache_block * target = NULL ;
91
+ /* find target list */
92
+ while ((list_idx < LIST_CNT ) && (len > block_size [list_idx ])) {
93
+ ++ list_idx ;
94
+ }
95
+ if (list_idx == LIST_CNT ) {
96
+ printf ("too much data to cache\n" );
97
+ return ;
98
+ }
99
+ cache_block * this_list = cache_lists [list_idx ];
100
+ /* find free block or LRU block as target block */
101
+ int64_t min_timestamp = get_timestamp ();
102
+ for (int j = 0 ; j < block_cnt [list_idx ]; ++ j ) {
103
+ if (this_list [j ].timestamp < min_timestamp ) {
104
+ target = & this_list [j ];
105
+ min_timestamp = target -> timestamp ;
106
+ if (!min_timestamp ) break ; /* free block found */
107
+ }
108
+ }
109
+ /* we can write to target block */
110
+ pthread_rwlock_wrlock (& target -> rwlock );
111
+ memcpy (target -> url , url , MAXLINE );
112
+ memcpy (target -> data , data , len );
113
+ target -> datasize = len ;
114
+ target -> timestamp = get_timestamp ();
115
+ pthread_rwlock_unlock (& target -> rwlock );
116
+ printf ("write content into cache\n" );
117
+ }
118
+
119
+ int64_t get_timestamp () {
120
+ struct timeval time ;
121
+ gettimeofday (& time , NULL );
122
+ int64_t s1 = (int64_t )(time .tv_sec ) * 1000 ;
123
+ int64_t s2 = (time .tv_usec / 1000 );
124
+ return s1 + s2 ;
125
+ }
0 commit comments