MXS-1262: Minor improvements to monitor journals

Moved 4 byte get/set into utils header. The byte packing functions in
maxscale/protocol/mysql.h should be migrated to the utils directory where
they can also be used by non-mysql code.

The temporary files are now generated with mkstemp. This will prevent
conflicts with multiple monitors operating on the same temporary journal
even though it is impossible in practice.

Added missing error messages to a couple of the functions.
This commit is contained in:
Markus Mäkelä 2017-08-11 11:35:13 +03:00
parent b768d3ca76
commit 9d3772a67e
2 changed files with 72 additions and 40 deletions

View File

@ -123,4 +123,35 @@ bool mxs_mkdir_all(const char *path, int mask);
long get_processor_count();
/**
* Store a 4 byte integer
*
* @param ptr Pointer where value is stored
* @param value Value to store
*
* @return The next byte after the stored value
*/
static inline uint8_t* mxs_set_byte4(uint8_t* ptr, uint32_t value)
{
*ptr++ = value;
*ptr++ = (value >> 8);
*ptr++ = (value >> 16);
*ptr++ = (value >> 24);
return ptr;
}
/**
* Read a 4 byte integer
*
* @param ptr Pointer where value is stored
* @param value Value to store
*
* @return The next byte after the stored value
*/
static inline uint32_t mxs_get_byte4(const uint8_t* ptr)
{
return ((uint32_t) ptr[0]) | ((uint32_t) ptr[1] << 8) |
((uint32_t) ptr[2] << 16) | ((uint32_t) ptr[3] << 24);
}
MXS_END_DECLS

View File

@ -1734,7 +1734,7 @@ json_t* monitor_relations_to_server(const SERVER* server, const char* host)
}
static const char journal_name[] = "monitor.dat";
static const char path_template[] = "%s/%s/";
static const char journal_template[] = "%s/%s/%s";
/**
* @brief Remove .tmp suffix and rename file
@ -1742,16 +1742,11 @@ static const char path_template[] = "%s/%s/";
* @param src File to rename
* @return True if file was successfully renamed
*/
static bool rename_tmp_file(const char *src)
static bool rename_tmp_file(MXS_MONITOR* monitor, const char *src)
{
char dest[strlen(src) + 1];
strcpy(dest, src);
char *tail = strrchr(dest, '.');
ss_dassert(tail && strcmp(tail, ".tmp") == 0);
*tail = '\0';
bool rval = true;
char dest[PATH_MAX + 1];
snprintf(dest, sizeof(dest), journal_template, get_datadir(), monitor->name, journal_name);
if (rename(src, dest) == -1)
{
@ -1772,19 +1767,29 @@ static bool rename_tmp_file(const char *src)
*/
static FILE* open_tmp_file(MXS_MONITOR *monitor, char *path)
{
int nbytes = snprintf(path, PATH_MAX, path_template, get_datadir(), monitor->name);
int nbytes = snprintf(path, PATH_MAX, journal_template, get_datadir(), monitor->name, "");
int max_bytes = PATH_MAX - (int)sizeof(journal_name);
FILE *rval = NULL;
if ((size_t)nbytes < PATH_MAX - sizeof(journal_name) && mxs_mkdir_all(path, 0744))
if (nbytes < max_bytes && mxs_mkdir_all(path, 0744))
{
strcat(path, journal_name);
strcat(path, ".tmp");
strcat(path, "XXXXXX");
int fd = mkstemp(path);
if ((rval = fopen(path, "wb")) == NULL)
if (fd == -1)
{
MXS_ERROR("Failed to open file '%s': %d, %s", path, errno, mxs_strerror(errno));
}
else
{
rval = fdopen(fd, "w");
}
}
else
{
MXS_ERROR("Path is too long: %d characters exceeds the maximum path "
"length of %d bytes", nbytes, max_bytes);
}
return rval;
@ -1798,16 +1803,13 @@ static FILE* open_tmp_file(MXS_MONITOR *monitor, char *path)
* PATH_MAX bytes long
* @param size Size of @c data
*/
static void store_data(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *master, char *data, uint32_t size)
static void store_data(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *master, uint8_t *data, uint32_t size)
{
char *ptr = data;
uint8_t* ptr = data;
/** Store the data length */
ss_dassert(sizeof(size) == MMB_LEN_BYTES);
*ptr++ = size;
*ptr++ = (size >> 8);
*ptr++ = (size >> 16);
*ptr++ = (size >> 24);
ptr = mxs_set_byte4(ptr, size);
/** Then the schema version */
*ptr++ = MMB_SCHEMA_VERSION;
@ -1816,23 +1818,22 @@ static void store_data(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *master, char *
for (MXS_MONITOR_SERVERS* db = monitor->databases; db; db = db->next)
{
*ptr++ = (char)SVT_SERVER; // Value type
strcpy(ptr, db->server->unique_name); // Name of the server
ptr += strlen(db->server->unique_name) + 1;
memcpy(ptr, db->server->unique_name, strlen(db->server->unique_name)); // Name of the server
ptr += strlen(db->server->unique_name);
*ptr++ = '\0'; // Null-terminate the string
uint32_t status = db->server->status; // Server status as 4 byte integer
ss_dassert(sizeof(status) == MMB_LEN_SERVER_STATUS);
*ptr++ = status;
*ptr++ = (status >> 8);
*ptr++ = (status >> 16);
*ptr++ = (status >> 24);
ptr = mxs_set_byte4(ptr, status);
}
/** Store the current root master if we have one */
if (master)
{
*ptr++ = (char)SVT_MASTER;
strcpy(ptr, master->server->unique_name);
ptr += strlen(master->server->unique_name) + 1;
memcpy(ptr, master->server->unique_name, strlen(master->server->unique_name));
ptr += strlen(master->server->unique_name);
*ptr++ = '\0'; // Null-terminate the string
}
/** Calculate the CRC32 for the complete payload minus the CRC32 bytes */
@ -1840,19 +1841,14 @@ static void store_data(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *master, char *
crc = crc32(crc, (uint8_t*)data + MMB_LEN_BYTES, size - MMB_LEN_CRC32);
ss_dassert(sizeof(crc) == MMB_LEN_CRC32);
*ptr++ = crc;
*ptr++ = (crc >> 8);
*ptr++ = (crc >> 16);
*ptr++ = (crc >> 24);
ptr = mxs_set_byte4(ptr, crc);
ss_dassert(ptr - data == size + MMB_LEN_BYTES);
}
static int get_data_file_path(MXS_MONITOR *monitor, char *path)
{
int rv = snprintf(path, PATH_MAX, path_template, get_datadir(), monitor->name);
strcat(path, journal_name);
return rv + sizeof(journal_name) - 1;
int rv = snprintf(path, PATH_MAX, journal_template, get_datadir(), monitor->name, journal_name);
return rv;
}
/**
@ -1874,6 +1870,11 @@ static FILE* open_data_file(MXS_MONITOR *monitor, char *path)
MXS_ERROR("Failed to open journal file: %d, %s", errno, mxs_strerror(errno));
}
}
else
{
MXS_ERROR("Path is too long: %d characters exceeds the maximum path "
"length of %d bytes", nbytes, PATH_MAX);
}
return rval;
}
@ -1908,7 +1909,7 @@ static const char* process_server(MXS_MONITOR *monitor, const char *data, const
ss_dassert(sptr);
sptr++;
uint32_t state = sptr[0] | (sptr[1] << 8) | (sptr[2] << 16) | (sptr[3] << 24);
uint32_t state = mxs_get_byte4(sptr);
db->mon_prev_status = state;
db->server->status_pending = state;
server_set_status_nolock(db->server, state);
@ -1950,7 +1951,7 @@ static const char* process_master(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS **ma
*/
static bool check_crc32(const uint8_t *data, uint32_t size, const uint8_t *crc_ptr)
{
uint32_t crc = crc_ptr[0] | (crc_ptr[1] << 8) | (crc_ptr[2] << 16) | (crc_ptr[3] << 24);
uint32_t crc = mxs_get_byte4(crc_ptr);
uint32_t calculated_crc = crc32(0L, NULL, 0);
calculated_crc = crc32(calculated_crc, data, size);
return calculated_crc == crc;
@ -2019,7 +2020,7 @@ void store_server_journal(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *master)
/** 4 bytes for file length, 1 byte for schema version and 4 bytes for CRC32 */
uint32_t buffer_size = size + MMB_LEN_BYTES;
char *data = (char*)MXS_MALLOC(buffer_size);
uint8_t *data = (uint8_t*)MXS_MALLOC(buffer_size);
char path[PATH_MAX + 1];
if (data)
@ -2034,7 +2035,7 @@ void store_server_journal(MXS_MONITOR *monitor, MXS_MONITOR_SERVERS *master)
/** Write the data to a temp file and rename it to the final name */
if (fwrite(data, 1, buffer_size, file) == buffer_size && fflush(file) == 0)
{
if (!rename_tmp_file(path))
if (!rename_tmp_file(monitor, path))
{
unlink(path);
}