mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 02:46:29 +01:00 
			
		
		
		
	 1c55b845e0
			
		
	
	
	1c55b845e0
	
	
	
		
			
			Added support to BACKUP STAGE to maria-backup
This is a port of the code from ES 10.6
See MDEV-5336 for backup stages description.
The following old options are not supported by the new code:
--rsync             ; This is because rsync will not work on tables
                      that are in used.
--no-backup-locks   ; This is disabled as mariadb-backup will always
                      use backup locks for better performance.
		
	
			
		
			
				
	
	
		
			263 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /******************************************************
 | |
| Copyright (c) 2011-2017 Percona LLC and/or its affiliates.
 | |
| 
 | |
| The xbstream format reader implementation.
 | |
| 
 | |
| This program is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; version 2 of the License.
 | |
| 
 | |
| This program is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with this program; if not, write to the Free Software
 | |
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
 | |
| 
 | |
| *******************************************************/
 | |
| 
 | |
| #include <my_global.h>
 | |
| #include <my_base.h>
 | |
| #include <zlib.h>
 | |
| #include "common.h"
 | |
| #include "xbstream.h"
 | |
| 
 | |
| /* Allocate 1 MB for the payload buffer initially */
 | |
| #define INIT_BUFFER_LEN (1024 * 1024)
 | |
| 
 | |
| #ifndef MY_OFF_T_MAX
 | |
| #define MY_OFF_T_MAX (~(my_off_t)0UL)
 | |
| #endif
 | |
| 
 | |
| struct xb_rstream_struct {
 | |
| 	my_off_t	offset;
 | |
| 	File 		fd;
 | |
| };
 | |
| 
 | |
| xb_rstream_t *
 | |
| xb_stream_read_new(void)
 | |
| {
 | |
| 	xb_rstream_t *stream;
 | |
| 
 | |
| 	stream = (xb_rstream_t *) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(xb_rstream_t), MYF(MY_FAE));
 | |
| 
 | |
| #ifdef _WIN32
 | |
| 	setmode(fileno(stdin), _O_BINARY);
 | |
| #endif
 | |
| 
 | |
| 	stream->fd = my_fileno(stdin);
 | |
| 	stream->offset = 0;
 | |
| 
 | |
| 	return stream;
 | |
| }
 | |
| 
 | |
| static inline
 | |
| xb_chunk_type_t
 | |
| validate_chunk_type(uchar code)
 | |
| {
 | |
| 	switch ((xb_chunk_type_t) code) {
 | |
| 	case XB_CHUNK_TYPE_PAYLOAD:
 | |
| 	case XB_CHUNK_TYPE_RENAME:
 | |
| 	case XB_CHUNK_TYPE_REMOVE:
 | |
| 	case XB_CHUNK_TYPE_SEEK:
 | |
| 	case XB_CHUNK_TYPE_EOF:
 | |
| 		return (xb_chunk_type_t) code;
 | |
| 	default:
 | |
| 		return XB_CHUNK_TYPE_UNKNOWN;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| xb_rstream_result_t
 | |
| xb_stream_validate_checksum(xb_rstream_chunk_t *chunk)
 | |
| {
 | |
| 	ulong	checksum;
 | |
| 	checksum = my_checksum(0, chunk->data, chunk->length);
 | |
| 	if (checksum != chunk->checksum) {
 | |
| 		msg("xb_stream_read_chunk(): invalid checksum at offset "
 | |
| 		    "0x%llx: expected 0x%lx, read 0x%lx.",
 | |
| 		    (ulonglong) chunk->checksum_offset, chunk->checksum,
 | |
| 		    checksum);
 | |
| 		return XB_STREAM_READ_ERROR;
 | |
| 	}
 | |
| 
 | |
| 	return XB_STREAM_READ_CHUNK;
 | |
| }
 | |
| 
 | |
| #define F_READ(buf,len)                                       	\
 | |
| 	do {                                                      	\
 | |
| 		if (xb_read_full(fd, (uchar *)buf, len) < len) {	\
 | |
| 			msg("xb_stream_read_chunk(): my_read() failed."); \
 | |
| 			goto err;                                 	\
 | |
| 		}							\
 | |
| 	} while (0)
 | |
| 
 | |
| xb_rstream_result_t
 | |
| xb_stream_read_chunk(xb_rstream_t *stream, xb_rstream_chunk_t *chunk)
 | |
| {
 | |
| 	uchar		tmpbuf[16];
 | |
| 	uchar		*ptr = tmpbuf;
 | |
| 	uint		pathlen;
 | |
| 	size_t		tbytes;
 | |
| 	ulonglong	ullval;
 | |
| 	File		fd = stream->fd;
 | |
| 
 | |
| 	xb_ad(sizeof(tmpbuf) >= CHUNK_HEADER_CONSTANT_LEN);
 | |
| 
 | |
| 	/* This is the only place where we expect EOF, so read with
 | |
| 	xb_read_full() rather than F_READ() */
 | |
| 	tbytes = xb_read_full(fd, ptr, CHUNK_HEADER_CONSTANT_LEN);
 | |
| 	if (tbytes == 0) {
 | |
| 		return XB_STREAM_READ_EOF;
 | |
| 	} else if (tbytes < CHUNK_HEADER_CONSTANT_LEN) {
 | |
| 		msg("xb_stream_read_chunk(): unexpected end of stream at "
 | |
| 		    "offset 0x%llx.", stream->offset);
 | |
| 		goto err;
 | |
| 	}
 | |
| 
 | |
| 	ptr = tmpbuf;
 | |
| 
 | |
| 	/* Chunk magic value */
 | |
| 	if (memcmp(tmpbuf, XB_STREAM_CHUNK_MAGIC, 8)) {
 | |
| 		msg("xb_stream_read_chunk(): wrong chunk magic at offset "
 | |
| 		    "0x%llx.", (ulonglong) stream->offset);
 | |
| 		goto err;
 | |
| 	}
 | |
| 	ptr += 8;
 | |
| 	stream->offset += 8;
 | |
| 
 | |
| 	/* Chunk flags */
 | |
| 	chunk->flags = *ptr++;
 | |
| 	stream->offset++;
 | |
| 
 | |
| 	/* Chunk type, ignore unknown ones if ignorable flag is set */
 | |
| 	chunk->type = validate_chunk_type(*ptr);
 | |
| 	if (chunk->type == XB_CHUNK_TYPE_UNKNOWN &&
 | |
| 	    !(chunk->flags & XB_STREAM_FLAG_IGNORABLE)) {
 | |
| 		msg("xb_stream_read_chunk(): unknown chunk type 0x%lu at "
 | |
| 		    "offset 0x%llx.", (ulong) *ptr,
 | |
| 		    (ulonglong) stream->offset);
 | |
| 		goto err;
 | |
| 	}
 | |
| 	ptr++;
 | |
| 	stream->offset++;
 | |
| 
 | |
| 	/* Path length */
 | |
| 	pathlen = uint4korr(ptr);
 | |
| 	if (pathlen >= FN_REFLEN) {
 | |
| 		msg("xb_stream_read_chunk(): path length (%lu) is too large at "
 | |
| 		    "offset 0x%llx.", (ulong) pathlen, stream->offset);
 | |
| 		goto err;
 | |
| 	}
 | |
| 	chunk->pathlen = pathlen;
 | |
| 	stream->offset +=4;
 | |
| 
 | |
| 	xb_ad((ptr + 4 - tmpbuf) == CHUNK_HEADER_CONSTANT_LEN);
 | |
| 
 | |
| 	/* Path */
 | |
| 	if (chunk->pathlen > 0) {
 | |
| 		F_READ((uchar *) chunk->path, pathlen);
 | |
| 		stream->offset += pathlen;
 | |
| 	}
 | |
| 	chunk->path[pathlen] = '\0';
 | |
| 
 | |
| 	if (chunk->type == XB_CHUNK_TYPE_EOF ||
 | |
| 			chunk->type == XB_CHUNK_TYPE_REMOVE) {
 | |
| 		return XB_STREAM_READ_CHUNK;
 | |
| 	}
 | |
| 
 | |
| 	if (chunk->type == XB_CHUNK_TYPE_RENAME) {
 | |
| 		F_READ(tmpbuf, 4);
 | |
| 		size_t new_pathlen = uint4korr(tmpbuf);
 | |
| 		if (new_pathlen >= FN_REFLEN) {
 | |
| 			msg("xb_stream_read_chunk(): path length (%lu) for new name of 'rename'"
 | |
| 				"	chunk is too large", (ulong) new_pathlen);
 | |
| 			goto err;
 | |
| 		}
 | |
| 		chunk->length = new_pathlen;
 | |
| 		stream->offset +=4;
 | |
| 	}
 | |
| 	else if (chunk->type == XB_CHUNK_TYPE_SEEK) {
 | |
| 		F_READ(tmpbuf, 8);
 | |
| 		chunk->offset = uint8korr(tmpbuf);
 | |
| 		stream->offset += 8;
 | |
| 		return XB_STREAM_READ_CHUNK;
 | |
| 	}
 | |
| 	else {
 | |
| 		/* Payload length */
 | |
| 		F_READ(tmpbuf, 16);
 | |
| 		ullval = uint8korr(tmpbuf);
 | |
| 		if (ullval > (ulonglong) SIZE_T_MAX) {
 | |
| 			msg("xb_stream_read_chunk(): chunk length is too large at "
 | |
| 					"offset 0x%llx: 0x%llx.", (ulonglong) stream->offset,
 | |
| 					ullval);
 | |
| 			goto err;
 | |
| 		}
 | |
| 		chunk->length = (size_t) ullval;
 | |
| 		stream->offset += 8;
 | |
| 
 | |
| 		/* Payload offset */
 | |
| 		ullval = uint8korr(tmpbuf + 8);
 | |
| 		if (ullval > (ulonglong) MY_OFF_T_MAX) {
 | |
| 			msg("xb_stream_read_chunk(): chunk offset is too large at "
 | |
| 					"offset 0x%llx: 0x%llx.", (ulonglong) stream->offset,
 | |
| 					ullval);
 | |
| 			goto err;
 | |
| 		}
 | |
| 		chunk->offset = (my_off_t) ullval;
 | |
| 		stream->offset += 8;
 | |
| 	}
 | |
| 
 | |
| 	/* Reallocate the buffer if needed, take into account trailing '\0' for
 | |
| 	new file name in the case of XB_CHUNK_TYPE_RENAME */
 | |
| 	if (chunk->length + 1 > chunk->buflen) {
 | |
| 		chunk->data = my_realloc(PSI_NOT_INSTRUMENTED, chunk->data,
 | |
| 					chunk->length + 1, MYF(MY_WME | MY_ALLOW_ZERO_PTR));
 | |
| 		if (chunk->data == NULL) {
 | |
| 			msg("xb_stream_read_chunk(): failed to increase buffer "
 | |
| 			    "to %lu bytes.", (ulong) chunk->length + 1);
 | |
| 			goto err;
 | |
| 		}
 | |
| 		chunk->buflen = chunk->length + 1;
 | |
| 	}
 | |
| 
 | |
| 	if (chunk->type == XB_CHUNK_TYPE_RENAME) {
 | |
| 		if (chunk->length == 0) {
 | |
| 			msg("xb_stream_read_chunk(): failed to read new name for file to rename "
 | |
| 				": %s", chunk->path);
 | |
| 			goto err;
 | |
| 		}
 | |
| 		F_READ(chunk->data, chunk->length);
 | |
| 		stream->offset += chunk->length;
 | |
| 		reinterpret_cast<char *>(chunk->data)[chunk->length] = '\0';
 | |
| 		++chunk->length;
 | |
| 	}
 | |
| 	else {
 | |
| 		/* Checksum */
 | |
| 		F_READ(tmpbuf, 4);
 | |
| 		chunk->checksum = uint4korr(tmpbuf);
 | |
| 		chunk->checksum_offset = stream->offset;
 | |
| 
 | |
| 		/* Payload */
 | |
| 		if (chunk->length > 0) {
 | |
| 			F_READ(chunk->data, chunk->length);
 | |
| 			stream->offset += chunk->length;
 | |
| 		}
 | |
| 
 | |
| 		stream->offset += 4;
 | |
| 	}
 | |
| 
 | |
| 	return XB_STREAM_READ_CHUNK;
 | |
| 
 | |
| err:
 | |
| 	return XB_STREAM_READ_ERROR;
 | |
| }
 | |
| 
 | |
| int
 | |
| xb_stream_read_done(xb_rstream_t *stream)
 | |
| {
 | |
| 	my_free(stream);
 | |
| 
 | |
| 	return 0;
 | |
| }
 |