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