blob: b16c40c67da7c2e34d5a5a22b0483b04ee2be244 [file] [log] [blame]
/** @file
Record message definitions
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "tscore/ink_platform.h"
#include "tscore/ink_memory.h"
#include "tscore/ink_align.h"
#include "P_RecCore.h"
#include "P_RecFile.h"
#include "P_RecMessage.h"
#include "P_RecUtils.h"
#include "P_RecCore.h"
#include "tscore/I_Layout.h"
#include "tscpp/util/MemSpan.h"
static RecMessageRecvCb g_recv_cb = nullptr;
static void *g_recv_cookie = nullptr;
//-------------------------------------------------------------------------
// RecMessageAlloc
//-------------------------------------------------------------------------
RecMessage *
RecMessageAlloc(RecMessageT msg_type, int initial_size)
{
RecMessage *msg;
msg = static_cast<RecMessage *>(ats_malloc(sizeof(RecMessageHdr) + initial_size));
memset(msg, 0, sizeof(RecMessageHdr) + initial_size);
msg->msg_type = msg_type;
msg->o_start = sizeof(RecMessageHdr);
msg->o_write = sizeof(RecMessageHdr);
msg->o_end = sizeof(RecMessageHdr) + initial_size;
msg->entries = 0;
return msg;
}
//-------------------------------------------------------------------------
// RecMessageFree
//-------------------------------------------------------------------------
int
RecMessageFree(RecMessage *msg)
{
ats_free(msg);
return REC_ERR_OKAY;
}
//-------------------------------------------------------------------------
// RecMessageMarshal_Realloc
//-------------------------------------------------------------------------
RecMessage *
RecMessageMarshal_Realloc(RecMessage *msg, const RecRecord *record)
{
int msg_ele_size;
int rec_name_len = -1;
int rec_data_str_len = -1;
int rec_data_def_str_len = -1;
int rec_cfg_chk_len = -1;
RecMessageEleHdr *ele_hdr;
RecRecord *r;
char *p;
// find out how much space we need
msg_ele_size = sizeof(RecMessageEleHdr) + sizeof(RecRecord);
if (record->name) {
rec_name_len = strlen(record->name) + 1;
msg_ele_size += rec_name_len;
}
if (record->data_type == RECD_STRING) {
if (record->data.rec_string) {
rec_data_str_len = strlen(record->data.rec_string) + 1;
msg_ele_size += rec_data_str_len;
}
if (record->data_default.rec_string) {
rec_data_def_str_len = strlen(record->data_default.rec_string) + 1;
msg_ele_size += rec_data_def_str_len;
}
}
if (REC_TYPE_IS_CONFIG(record->rec_type) && (record->config_meta.check_expr)) {
rec_cfg_chk_len = strlen(record->config_meta.check_expr) + 1;
msg_ele_size += rec_cfg_chk_len;
}
// XXX: this is NOT 8 byte alignment
// msg_ele_size = 5;
// (msg_ele_size + 7) & ~7 == 5 !!!
// msg_ele_size = (msg_ele_size + 7) & ~7; // 8 byte alignment
msg_ele_size = INK_ALIGN_DEFAULT(msg_ele_size); // 8 byte alignment
// get some space in our buffer
while (msg->o_end - msg->o_write < msg_ele_size) {
int realloc_size = (msg->o_end - msg->o_start) * 2;
msg = static_cast<RecMessage *>(ats_realloc(msg, sizeof(RecMessageHdr) + realloc_size));
msg->o_end = msg->o_start + realloc_size;
}
ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_write);
// The following memset() is pretty CPU intensive, replacing it with something
// like the below would reduce CPU usage a fair amount. /leif.
// *((char*)msg + msg->o_write) = 0;
memset(reinterpret_cast<char *>(msg) + msg->o_write, 0, msg->o_end - msg->o_write);
msg->o_write += msg_ele_size;
// store the record
ele_hdr->magic = REC_MESSAGE_ELE_MAGIC;
ele_hdr->o_next = msg->o_write;
p = reinterpret_cast<char *>(ele_hdr) + sizeof(RecMessageEleHdr);
memcpy(p, record, sizeof(RecRecord));
r = reinterpret_cast<RecRecord *>(p);
p += sizeof(RecRecord);
if (rec_name_len != -1) {
ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_name_len);
memcpy(p, record->name, rec_name_len);
r->name = (char *)((uintptr_t)p - (uintptr_t)r);
p += rec_name_len;
}
if (rec_data_str_len != -1) {
ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_data_str_len);
memcpy(p, record->data.rec_string, rec_data_str_len);
r->data.rec_string = (char *)((uintptr_t)p - (uintptr_t)r);
p += rec_data_str_len;
}
if (rec_data_def_str_len != -1) {
ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_data_def_str_len);
memcpy(p, record->data_default.rec_string, rec_data_def_str_len);
r->data_default.rec_string = (char *)((uintptr_t)p - (uintptr_t)r);
p += rec_data_def_str_len;
}
if (rec_cfg_chk_len != -1) {
ink_assert((msg->o_end - ((uintptr_t)p - (uintptr_t)msg)) >= (uintptr_t)rec_cfg_chk_len);
memcpy(p, record->config_meta.check_expr, rec_cfg_chk_len);
r->config_meta.check_expr = (char *)((uintptr_t)p - (uintptr_t)r);
}
msg->entries += 1;
return msg;
}
//-------------------------------------------------------------------------
// RecMessageUnmarshalFirst
//-------------------------------------------------------------------------
int
RecMessageUnmarshalFirst(RecMessage *msg, RecMessageItr *itr, RecRecord **record)
{
itr->ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_start);
itr->next = 1;
return RecMessageUnmarshalNext(msg, nullptr, record);
}
//-------------------------------------------------------------------------
// RecMessageUnmarshalNext
//-------------------------------------------------------------------------
int
RecMessageUnmarshalNext(RecMessage *msg, RecMessageItr *itr, RecRecord **record)
{
RecMessageEleHdr *eh;
RecRecord *r;
if (itr == nullptr) {
if (msg->entries == 0) {
return REC_ERR_FAIL;
} else {
eh = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + msg->o_start);
}
} else {
if (itr->next >= msg->entries) {
return REC_ERR_FAIL;
}
itr->ele_hdr = reinterpret_cast<RecMessageEleHdr *>(reinterpret_cast<char *>(msg) + itr->ele_hdr->o_next);
itr->next += 1;
eh = itr->ele_hdr;
}
ink_assert(eh->magic == REC_MESSAGE_ELE_MAGIC);
// If the file is corrupt, ignore the the rest of the file.
if (eh->magic != REC_MESSAGE_ELE_MAGIC) {
Warning("Persistent statistics file records.stat is corrupted. Ignoring the rest of the file\n");
return REC_ERR_FAIL;
}
r = reinterpret_cast<RecRecord *>(reinterpret_cast<char *>(eh) + sizeof(RecMessageEleHdr));
if (r->name) {
r->name = reinterpret_cast<char *>(r) + (intptr_t)(r->name);
}
if (r->data_type == RECD_STRING) {
if (r->data.rec_string) {
r->data.rec_string = reinterpret_cast<char *>(r) + (intptr_t)(r->data.rec_string);
}
if (r->data_default.rec_string) {
r->data_default.rec_string = reinterpret_cast<char *>(r) + (intptr_t)(r->data_default.rec_string);
}
}
if (REC_TYPE_IS_CONFIG(r->rec_type) && (r->config_meta.check_expr)) {
r->config_meta.check_expr = reinterpret_cast<char *>(r) + (intptr_t)(r->config_meta.check_expr);
}
*record = r;
return REC_ERR_OKAY;
}
//-------------------------------------------------------------------------
// RecMessageRegisterRecvCb
//-------------------------------------------------------------------------
int
RecMessageRegisterRecvCb(RecMessageRecvCb recv_cb, void *cookie)
{
if (g_recv_cb) {
return REC_ERR_FAIL;
}
g_recv_cookie = cookie;
g_recv_cb = recv_cb;
return REC_ERR_OKAY;
}
//-------------------------------------------------------------------------
// RecMessageRecvThis
//-------------------------------------------------------------------------
void
RecMessageRecvThis(ts::MemSpan<void> span)
{
RecMessage *msg = static_cast<RecMessage *>(span.data());
g_recv_cb(msg, msg->msg_type, g_recv_cookie);
}
//-------------------------------------------------------------------------
// RecMessageReadFromDisk
//-------------------------------------------------------------------------
RecMessage *
RecMessageReadFromDisk(const char *fpath)
{
RecMessageHdr msg_hdr;
RecMessage *msg = nullptr;
RecHandle h_file;
int bytes_read;
if ((h_file = RecFileOpenR(fpath)) == REC_HANDLE_INVALID) {
goto Lerror;
}
if (RecFileRead(h_file, reinterpret_cast<char *>(&msg_hdr), sizeof(RecMessageHdr), &bytes_read) == REC_ERR_FAIL) {
goto Lerror;
}
msg = static_cast<RecMessage *>(ats_malloc((msg_hdr.o_end - msg_hdr.o_start) + sizeof(RecMessageHdr)));
memcpy(msg, &msg_hdr, sizeof(RecMessageHdr));
if (RecSnapFileRead(h_file, reinterpret_cast<char *>(msg) + msg_hdr.o_start, msg_hdr.o_end - msg_hdr.o_start, &bytes_read) ==
REC_ERR_FAIL) {
goto Lerror;
}
goto Ldone;
Lerror:
ats_free(msg);
msg = nullptr;
Ldone:
if (h_file != REC_HANDLE_INVALID) {
RecFileClose(h_file);
}
return msg;
}
//-------------------------------------------------------------------------
// RecMessageWriteToDisk
//-------------------------------------------------------------------------
int
RecMessageWriteToDisk(RecMessage *msg, const char *fpath)
{
int msg_size;
RecHandle h_file;
int bytes_written;
// Cap the message (e.g. when we read it, o_end should reflect the
// size of the new buffer that we write to disk, not the size of the
// buffer in memory).
msg->o_end = msg->o_write;
msg_size = sizeof(RecMessageHdr) + (msg->o_write - msg->o_start);
if ((h_file = RecFileOpenW(fpath)) != REC_HANDLE_INVALID) {
if (RecSnapFileWrite(h_file, reinterpret_cast<char *>(msg), msg_size, &bytes_written) == REC_ERR_FAIL) {
RecFileClose(h_file);
return REC_ERR_FAIL;
}
RecFileClose(h_file);
}
return REC_ERR_OKAY;
}