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 Action *
link(Continuation * cont,const CacheKey * from,const CacheKey * to,CacheFragType type,const char * hostname,int host_len)27 Cache::link(Continuation *cont, const CacheKey *from, const CacheKey *to, CacheFragType type, const char *hostname, int host_len)
28 {
29   if (!CacheProcessor::IsCacheReady(type)) {
30     cont->handleEvent(CACHE_EVENT_LINK_FAILED, nullptr);
31     return ACTION_RESULT_DONE;
32   }
33 
34   ink_assert(caches[type] == this);
35 
36   CacheVC *c         = new_CacheVC(cont);
37   c->vol             = key_to_vol(from, hostname, host_len);
38   c->write_len       = sizeof(*to); // so that the earliest_key will be used
39   c->f.use_first_key = 1;
40   c->first_key       = *from;
41   c->earliest_key    = *to;
42 
43   c->buf = new_IOBufferData(BUFFER_SIZE_INDEX_512);
44 #ifdef DEBUG
45   Doc *doc = reinterpret_cast<Doc *>(c->buf->data());
46   memcpy(doc->data(), to, sizeof(*to)); // doublecheck
47 #endif
48 
49   SET_CONTINUATION_HANDLER(c, &CacheVC::linkWrite);
50 
51   if (c->do_write_lock() == EVENT_DONE) {
52     return ACTION_RESULT_DONE;
53   } else {
54     return &c->_action;
55   }
56 }
57 
58 int
linkWrite(int event,Event *)59 CacheVC::linkWrite(int event, Event * /* e ATS_UNUSED */)
60 {
61   ink_assert(event == AIO_EVENT_DONE);
62   set_io_not_in_progress();
63   dir_insert(&first_key, vol, &dir);
64   if (_action.cancelled) {
65     goto Ldone;
66   }
67   if (io.ok()) {
68     _action.continuation->handleEvent(CACHE_EVENT_LINK, nullptr);
69   } else {
70     _action.continuation->handleEvent(CACHE_EVENT_LINK_FAILED, nullptr);
71   }
72 Ldone:
73   return free_CacheVC(this);
74 }
75 
76 Action *
deref(Continuation * cont,const CacheKey * key,CacheFragType type,const char * hostname,int host_len)77 Cache::deref(Continuation *cont, const CacheKey *key, CacheFragType type, const char *hostname, int host_len)
78 {
79   if (!CacheProcessor::IsCacheReady(type)) {
80     cont->handleEvent(CACHE_EVENT_DEREF_FAILED, nullptr);
81     return ACTION_RESULT_DONE;
82   }
83 
84   ink_assert(caches[type] == this);
85 
86   Vol *vol = key_to_vol(key, hostname, host_len);
87   Dir result;
88   Dir *last_collision = nullptr;
89   CacheVC *c          = nullptr;
90   {
91     MUTEX_TRY_LOCK(lock, vol->mutex, cont->mutex->thread_holding);
92     if (lock.is_locked()) {
93       if (!dir_probe(key, vol, &result, &last_collision)) {
94         cont->handleEvent(CACHE_EVENT_DEREF_FAILED, (void *)-ECACHE_NO_DOC);
95         return ACTION_RESULT_DONE;
96       }
97     }
98     c = new_CacheVC(cont);
99     SET_CONTINUATION_HANDLER(c, &CacheVC::derefRead);
100     c->first_key = c->key = *key;
101     c->vol                = vol;
102     c->dir                = result;
103     c->last_collision     = last_collision;
104 
105     if (!lock.is_locked()) {
106       c->mutex->thread_holding->schedule_in_local(c, HRTIME_MSECONDS(cache_config_mutex_retry_delay));
107       return &c->_action;
108     }
109 
110     switch (c->do_read_call(&c->key)) {
111     case EVENT_DONE:
112       return ACTION_RESULT_DONE;
113     case EVENT_RETURN:
114       goto Lcallreturn;
115     default:
116       return &c->_action;
117     }
118   }
119 Lcallreturn:
120   if (c->handleEvent(AIO_EVENT_DONE, nullptr) == EVENT_DONE) {
121     return ACTION_RESULT_DONE;
122   } else {
123     return &c->_action;
124   }
125 }
126 
127 int
derefRead(int,Event *)128 CacheVC::derefRead(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
129 {
130   Doc *doc = nullptr;
131 
132   cancel_trigger();
133   set_io_not_in_progress();
134   if (_action.cancelled) {
135     return free_CacheVC(this);
136   }
137   if (!buf) {
138     goto Lcollision;
139   }
140   if (static_cast<int>(io.aio_result) != static_cast<int>(io.aiocb.aio_nbytes)) {
141     goto Ldone;
142   }
143   if (!dir_agg_valid(vol, &dir)) {
144     last_collision = nullptr;
145     goto Lcollision;
146   }
147   doc = reinterpret_cast<Doc *>(buf->data());
148   if (!(doc->first_key == key)) {
149     goto Lcollision;
150   }
151 #ifdef DEBUG
152   ink_assert(!memcmp(doc->data(), &doc->key, sizeof(doc->key)));
153 #endif
154   _action.continuation->handleEvent(CACHE_EVENT_DEREF, (void *)&doc->key);
155   return free_CacheVC(this);
156 
157 Lcollision : {
158   CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding);
159   if (!lock.is_locked()) {
160     mutex->thread_holding->schedule_in_local(this, HRTIME_MSECONDS(cache_config_mutex_retry_delay));
161     return EVENT_CONT;
162   }
163   if (dir_probe(&key, vol, &dir, &last_collision)) {
164     int ret = do_read_call(&first_key);
165     if (ret == EVENT_RETURN) {
166       goto Lcallreturn;
167     }
168     return ret;
169   }
170 }
171 Ldone:
172   _action.continuation->handleEvent(CACHE_EVENT_DEREF_FAILED, (void *)-ECACHE_NO_DOC);
173   return free_CacheVC(this);
174 Lcallreturn:
175   return handleEvent(AIO_EVENT_DONE, nullptr); // hopefully a tail call
176 }
177