/src/trafficserver/src/records/RecMessage.cc
Line | Count | Source |
1 | | /** @file |
2 | | |
3 | | Record message definitions |
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 "tscore/ink_platform.h" |
25 | | #include "tscore/ink_memory.h" |
26 | | #include "tscore/ink_align.h" |
27 | | |
28 | | #include "P_RecCore.h" |
29 | | #include "P_RecFile.h" |
30 | | #include "P_RecMessage.h" |
31 | | #include "P_RecUtils.h" |
32 | | #include "P_RecCore.h" |
33 | | #include "tscore/Layout.h" |
34 | | #include "swoc/MemSpan.h" |
35 | | |
36 | | static RecMessageRecvCb g_recv_cb = nullptr; |
37 | | static void *g_recv_cookie = nullptr; |
38 | | |
39 | | //------------------------------------------------------------------------- |
40 | | // RecMessageAlloc |
41 | | //------------------------------------------------------------------------- |
42 | | RecMessage * |
43 | | RecMessageAlloc(RecMessageT msg_type, int initial_size) |
44 | 0 | { |
45 | 0 | RecMessage *msg; |
46 | |
|
47 | 0 | msg = static_cast<RecMessage *>(ats_malloc(sizeof(RecMessageHdr) + initial_size)); |
48 | 0 | memset(msg, 0, sizeof(RecMessageHdr) + initial_size); |
49 | 0 | msg->msg_type = msg_type; |
50 | 0 | msg->o_start = sizeof(RecMessageHdr); |
51 | 0 | msg->o_write = sizeof(RecMessageHdr); |
52 | 0 | msg->o_end = sizeof(RecMessageHdr) + initial_size; |
53 | 0 | msg->entries = 0; |
54 | |
|
55 | 0 | return msg; |
56 | 0 | } |
57 | | |
58 | | //------------------------------------------------------------------------- |
59 | | // RecMessageFree |
60 | | //------------------------------------------------------------------------- |
61 | | |
62 | | int |
63 | | RecMessageFree(RecMessage *msg) |
64 | 0 | { |
65 | 0 | ats_free(msg); |
66 | 0 | return REC_ERR_OKAY; |
67 | 0 | } |
68 | | |
69 | | //------------------------------------------------------------------------- |
70 | | // RecMessageMarshal_Realloc |
71 | | //------------------------------------------------------------------------- |
72 | | RecMessage * |
73 | | RecMessageMarshal_Realloc(RecMessage *msg, const RecRecord *record) |
74 | 0 | { |
75 | 0 | int msg_ele_size; |
76 | 0 | int rec_name_len = -1; |
77 | 0 | int rec_data_str_len = -1; |
78 | 0 | int rec_data_def_str_len = -1; |
79 | 0 | int rec_cfg_chk_len = -1; |
80 | 0 | RecMessageEleHdr *ele_hdr; |
81 | 0 | RecRecord *r; |
82 | 0 | char *p; |
83 | | |
84 | | // find out how much space we need |
85 | 0 | msg_ele_size = sizeof(RecMessageEleHdr) + sizeof(RecRecord); |
86 | 0 | if (record->name) { |
87 | 0 | rec_name_len = strlen(record->name) + 1; |
88 | 0 | msg_ele_size += rec_name_len; |
89 | 0 | } |
90 | 0 | if (record->data_type == RECD_STRING) { |
91 | 0 | if (record->data.rec_string) { |
92 | 0 | rec_data_str_len = strlen(record->data.rec_string) + 1; |
93 | 0 | msg_ele_size += rec_data_str_len; |
94 | 0 | } |
95 | 0 | if (record->data_default.rec_string) { |
96 | 0 | rec_data_def_str_len = strlen(record->data_default.rec_string) + 1; |
97 | 0 | msg_ele_size += rec_data_def_str_len; |
98 | 0 | } |
99 | 0 | } |
100 | 0 | if (REC_TYPE_IS_CONFIG(record->rec_type) && (record->config_meta.check_expr)) { |
101 | 0 | rec_cfg_chk_len = strlen(record->config_meta.check_expr) + 1; |
102 | 0 | msg_ele_size += rec_cfg_chk_len; |
103 | 0 | } |
104 | | // XXX: this is NOT 8 byte alignment |
105 | | // msg_ele_size = 5; |
106 | | // (msg_ele_size + 7) & ~7 == 5 !!! |
107 | | // msg_ele_size = (msg_ele_size + 7) & ~7; // 8 byte alignment |
108 | |
|
109 | 0 | msg_ele_size = INK_ALIGN_DEFAULT(msg_ele_size); // 8 byte alignment |
110 | | // get some space in our buffer |
111 | 0 | while (msg->o_end - msg->o_write < msg_ele_size) { |
112 | 0 | int realloc_size = (msg->o_end - msg->o_start) * 2; |
113 | 0 | msg = static_cast<RecMessage *>(ats_realloc(msg, sizeof(RecMessageHdr) + realloc_size)); |
114 | 0 | msg->o_end = msg->o_start + realloc_size; |
115 | 0 | } |
116 | 0 | ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_write); |
117 | | // The following memset() is pretty CPU intensive, replacing it with something |
118 | | // like the below would reduce CPU usage a fair amount. /leif. |
119 | | // *((char*)msg + msg->o_write) = 0; |
120 | 0 | memset(reinterpret_cast<char *>(msg) + msg->o_write, 0, msg->o_end - msg->o_write); |
121 | 0 | msg->o_write += msg_ele_size; |
122 | | |
123 | | // store the record |
124 | 0 | ele_hdr->magic = REC_MESSAGE_ELE_MAGIC; |
125 | 0 | ele_hdr->o_next = msg->o_write; |
126 | 0 | p = reinterpret_cast<char *>(ele_hdr) + sizeof(RecMessageEleHdr); |
127 | 0 | memcpy(p, record, sizeof(RecRecord)); |
128 | 0 | r = reinterpret_cast<RecRecord *>(p); |
129 | 0 | p += sizeof(RecRecord); |
130 | 0 | if (rec_name_len != -1) { |
131 | 0 | ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_name_len); |
132 | 0 | memcpy(p, record->name, rec_name_len); |
133 | 0 | r->name = (char *)((uintptr_t)p - (uintptr_t)r); |
134 | 0 | p += rec_name_len; |
135 | 0 | } |
136 | 0 | if (rec_data_str_len != -1) { |
137 | 0 | ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_data_str_len); |
138 | 0 | memcpy(p, record->data.rec_string, rec_data_str_len); |
139 | 0 | r->data.rec_string = (char *)((uintptr_t)p - (uintptr_t)r); |
140 | 0 | p += rec_data_str_len; |
141 | 0 | } |
142 | 0 | if (rec_data_def_str_len != -1) { |
143 | 0 | ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_data_def_str_len); |
144 | 0 | memcpy(p, record->data_default.rec_string, rec_data_def_str_len); |
145 | 0 | r->data_default.rec_string = (char *)((uintptr_t)p - (uintptr_t)r); |
146 | 0 | p += rec_data_def_str_len; |
147 | 0 | } |
148 | 0 | if (rec_cfg_chk_len != -1) { |
149 | 0 | ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_cfg_chk_len); |
150 | 0 | memcpy(p, record->config_meta.check_expr, rec_cfg_chk_len); |
151 | 0 | r->config_meta.check_expr = (char *)((uintptr_t)p - (uintptr_t)r); |
152 | 0 | } |
153 | |
|
154 | 0 | msg->entries += 1; |
155 | |
|
156 | 0 | return msg; |
157 | 0 | } |
158 | | |
159 | | //------------------------------------------------------------------------- |
160 | | // RecMessageUnmarshalFirst |
161 | | //------------------------------------------------------------------------- |
162 | | |
163 | | int |
164 | | RecMessageUnmarshalFirst(RecMessage *msg, RecMessageItr *itr, RecRecord **record) |
165 | 0 | { |
166 | 0 | itr->ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_start); |
167 | 0 | itr->next = 1; |
168 | |
|
169 | 0 | return RecMessageUnmarshalNext(msg, nullptr, record); |
170 | 0 | } |
171 | | |
172 | | //------------------------------------------------------------------------- |
173 | | // RecMessageUnmarshalNext |
174 | | //------------------------------------------------------------------------- |
175 | | |
176 | | int |
177 | | RecMessageUnmarshalNext(RecMessage *msg, RecMessageItr *itr, RecRecord **record) |
178 | 0 | { |
179 | 0 | RecMessageEleHdr *eh; |
180 | 0 | RecRecord *r; |
181 | |
|
182 | 0 | if (itr == nullptr) { |
183 | 0 | if (msg->entries == 0) { |
184 | 0 | return REC_ERR_FAIL; |
185 | 0 | } else { |
186 | 0 | eh = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_start); |
187 | 0 | } |
188 | 0 | } else { |
189 | 0 | if (itr->next >= msg->entries) { |
190 | 0 | return REC_ERR_FAIL; |
191 | 0 | } |
192 | 0 | itr->ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + itr->ele_hdr->o_next); |
193 | 0 | itr->next += 1; |
194 | 0 | eh = itr->ele_hdr; |
195 | 0 | } |
196 | | |
197 | 0 | ink_assert(eh->magic == REC_MESSAGE_ELE_MAGIC); |
198 | | |
199 | | // If the file is corrupt, ignore the rest of the file. |
200 | 0 | if (eh->magic != REC_MESSAGE_ELE_MAGIC) { |
201 | 0 | Warning("Persistent statistics file records.stat is corrupted. Ignoring the rest of the file\n"); |
202 | 0 | return REC_ERR_FAIL; |
203 | 0 | } |
204 | | |
205 | 0 | r = reinterpret_cast<RecRecord *>(reinterpret_cast<char *>(eh) + sizeof(RecMessageEleHdr)); |
206 | |
|
207 | 0 | if (r->name) { |
208 | 0 | r->name = reinterpret_cast<char *>(r) + (intptr_t)(r->name); |
209 | 0 | } |
210 | 0 | if (r->data_type == RECD_STRING) { |
211 | 0 | if (r->data.rec_string) { |
212 | 0 | r->data.rec_string = reinterpret_cast<char *>(r) + (intptr_t)(r->data.rec_string); |
213 | 0 | } |
214 | 0 | if (r->data_default.rec_string) { |
215 | 0 | r->data_default.rec_string = reinterpret_cast<char *>(r) + (intptr_t)(r->data_default.rec_string); |
216 | 0 | } |
217 | 0 | } |
218 | 0 | if (REC_TYPE_IS_CONFIG(r->rec_type) && (r->config_meta.check_expr)) { |
219 | 0 | r->config_meta.check_expr = reinterpret_cast<char *>(r) + (intptr_t)(r->config_meta.check_expr); |
220 | 0 | } |
221 | |
|
222 | 0 | *record = r; |
223 | |
|
224 | 0 | return REC_ERR_OKAY; |
225 | 0 | } |
226 | | |
227 | | //------------------------------------------------------------------------- |
228 | | // RecMessageRegisterRecvCb |
229 | | //------------------------------------------------------------------------- |
230 | | |
231 | | int |
232 | | RecMessageRegisterRecvCb(RecMessageRecvCb recv_cb, void *cookie) |
233 | 0 | { |
234 | 0 | if (g_recv_cb) { |
235 | 0 | return REC_ERR_FAIL; |
236 | 0 | } |
237 | 0 | g_recv_cookie = cookie; |
238 | 0 | g_recv_cb = recv_cb; |
239 | |
|
240 | 0 | return REC_ERR_OKAY; |
241 | 0 | } |
242 | | |
243 | | //------------------------------------------------------------------------- |
244 | | // RecMessageReadFromDisk |
245 | | //------------------------------------------------------------------------- |
246 | | |
247 | | RecMessage * |
248 | | RecMessageReadFromDisk(const char *fpath) |
249 | 0 | { |
250 | 0 | RecMessageHdr msg_hdr; |
251 | 0 | RecMessage *msg = nullptr; |
252 | 0 | RecHandle h_file; |
253 | 0 | int bytes_read; |
254 | |
|
255 | 0 | if ((h_file = RecFileOpenR(fpath)) == REC_HANDLE_INVALID) { |
256 | 0 | goto Lerror; |
257 | 0 | } |
258 | 0 | if (RecFileRead(h_file, reinterpret_cast<char *>(&msg_hdr), sizeof(RecMessageHdr), &bytes_read) == REC_ERR_FAIL) { |
259 | 0 | goto Lerror; |
260 | 0 | } |
261 | 0 | msg = static_cast<RecMessage *>(ats_malloc((msg_hdr.o_end - msg_hdr.o_start) + sizeof(RecMessageHdr))); |
262 | 0 | memcpy(msg, &msg_hdr, sizeof(RecMessageHdr)); |
263 | 0 | if (RecSnapFileRead(h_file, reinterpret_cast<char *>(msg) + msg_hdr.o_start, msg_hdr.o_end - msg_hdr.o_start, &bytes_read) == |
264 | 0 | REC_ERR_FAIL) { |
265 | 0 | goto Lerror; |
266 | 0 | } |
267 | | |
268 | 0 | goto Ldone; |
269 | | |
270 | 0 | Lerror: |
271 | 0 | ats_free(msg); |
272 | 0 | msg = nullptr; |
273 | |
|
274 | 0 | Ldone: |
275 | 0 | if (h_file != REC_HANDLE_INVALID) { |
276 | 0 | RecFileClose(h_file); |
277 | 0 | } |
278 | |
|
279 | 0 | return msg; |
280 | 0 | } |
281 | | |
282 | | //------------------------------------------------------------------------- |
283 | | // RecMessageWriteToDisk |
284 | | //------------------------------------------------------------------------- |
285 | | |
286 | | int |
287 | | RecMessageWriteToDisk(RecMessage *msg, const char *fpath) |
288 | 0 | { |
289 | 0 | int msg_size; |
290 | 0 | RecHandle h_file; |
291 | 0 | int bytes_written; |
292 | | |
293 | | // Cap the message (e.g. when we read it, o_end should reflect the |
294 | | // size of the new buffer that we write to disk, not the size of the |
295 | | // buffer in memory). |
296 | 0 | msg->o_end = msg->o_write; |
297 | |
|
298 | 0 | msg_size = sizeof(RecMessageHdr) + (msg->o_write - msg->o_start); |
299 | 0 | if ((h_file = RecFileOpenW(fpath)) != REC_HANDLE_INVALID) { |
300 | 0 | if (RecSnapFileWrite(h_file, reinterpret_cast<char *>(msg), msg_size, &bytes_written) == REC_ERR_FAIL) { |
301 | 0 | RecFileClose(h_file); |
302 | 0 | return REC_ERR_FAIL; |
303 | 0 | } |
304 | 0 | RecFileClose(h_file); |
305 | 0 | } |
306 | | |
307 | 0 | return REC_ERR_OKAY; |
308 | 0 | } |