mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Rename bbstreamer to astreamer.
I (rhaas) intended "bbstreamer" to stand for "base backup streamer," but that implies that this infrastructure can only ever be used by pg_basebackup. In fact, it is a generally useful way of streaming data from a tar or compressed tar file, and it could be extended to work with other archive formats as well if we ever wanted to do that. Hence, rename it to "astreamer" (archive streamer) in preparation for reusing the infrastructure from pg_verifybackup (and perhaps eventually also other utilities, such as pg_combinebackup or pg_waldump). This is purely a renaming commit. Comment adjustments and relocation of the actual code to someplace from which it can be reused are left to future commits. Amul Sul, reviewed by Sravan Kumar and by me. Discussion: http://postgr.es/m/CAAJ_b94StvLWrc_p4q-f7n3OPfr6GhL8_XuAg2aAaYZp1tF-nw@mail.gmail.com
This commit is contained in:
@ -37,12 +37,12 @@ OBJS = \
|
|||||||
|
|
||||||
BBOBJS = \
|
BBOBJS = \
|
||||||
pg_basebackup.o \
|
pg_basebackup.o \
|
||||||
bbstreamer_file.o \
|
astreamer_file.o \
|
||||||
bbstreamer_gzip.o \
|
astreamer_gzip.o \
|
||||||
bbstreamer_inject.o \
|
astreamer_inject.o \
|
||||||
bbstreamer_lz4.o \
|
astreamer_lz4.o \
|
||||||
bbstreamer_tar.o \
|
astreamer_tar.o \
|
||||||
bbstreamer_zstd.o
|
astreamer_zstd.o
|
||||||
|
|
||||||
all: pg_basebackup pg_createsubscriber pg_receivewal pg_recvlogical
|
all: pg_basebackup pg_createsubscriber pg_receivewal pg_recvlogical
|
||||||
|
|
||||||
|
226
src/bin/pg_basebackup/astreamer.h
Normal file
226
src/bin/pg_basebackup/astreamer.h
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* astreamer.h
|
||||||
|
*
|
||||||
|
* Each tar archive returned by the server is passed to one or more
|
||||||
|
* astreamer objects for further processing. The astreamer may do
|
||||||
|
* something simple, like write the archive to a file, perhaps after
|
||||||
|
* compressing it, but it can also do more complicated things, like
|
||||||
|
* annotating the byte stream to indicate which parts of the data
|
||||||
|
* correspond to tar headers or trailing padding, vs. which parts are
|
||||||
|
* payload data. A subsequent astreamer may use this information to
|
||||||
|
* make further decisions about how to process the data; for example,
|
||||||
|
* it might choose to modify the archive contents.
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* src/bin/pg_basebackup/astreamer.h
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASTREAMER_H
|
||||||
|
#define ASTREAMER_H
|
||||||
|
|
||||||
|
#include "common/compression.h"
|
||||||
|
#include "lib/stringinfo.h"
|
||||||
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
struct astreamer;
|
||||||
|
struct astreamer_ops;
|
||||||
|
typedef struct astreamer astreamer;
|
||||||
|
typedef struct astreamer_ops astreamer_ops;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each chunk of archive data passed to a astreamer is classified into one
|
||||||
|
* of these categories. When data is first received from the remote server,
|
||||||
|
* each chunk will be categorized as ASTREAMER_UNKNOWN, and the chunks will
|
||||||
|
* be of whatever size the remote server chose to send.
|
||||||
|
*
|
||||||
|
* If the archive is parsed (e.g. see astreamer_tar_parser_new()), then all
|
||||||
|
* chunks should be labelled as one of the other types listed here. In
|
||||||
|
* addition, there should be exactly one ASTREAMER_MEMBER_HEADER chunk and
|
||||||
|
* exactly one ASTREAMER_MEMBER_TRAILER chunk per archive member, even if
|
||||||
|
* that means a zero-length call. There can be any number of
|
||||||
|
* ASTREAMER_MEMBER_CONTENTS chunks in between those calls. There
|
||||||
|
* should exactly ASTREAMER_ARCHIVE_TRAILER chunk, and it should follow the
|
||||||
|
* last ASTREAMER_MEMBER_TRAILER chunk.
|
||||||
|
*
|
||||||
|
* In theory, we could need other classifications here, such as a way of
|
||||||
|
* indicating an archive header, but the "tar" format doesn't need anything
|
||||||
|
* else, so for the time being there's no point.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ASTREAMER_UNKNOWN,
|
||||||
|
ASTREAMER_MEMBER_HEADER,
|
||||||
|
ASTREAMER_MEMBER_CONTENTS,
|
||||||
|
ASTREAMER_MEMBER_TRAILER,
|
||||||
|
ASTREAMER_ARCHIVE_TRAILER,
|
||||||
|
} astreamer_archive_context;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each chunk of data that is classified as ASTREAMER_MEMBER_HEADER,
|
||||||
|
* ASTREAMER_MEMBER_CONTENTS, or ASTREAMER_MEMBER_TRAILER should also
|
||||||
|
* pass a pointer to an instance of this struct. The details are expected
|
||||||
|
* to be present in the archive header and used to fill the struct, after
|
||||||
|
* which all subsequent calls for the same archive member are expected to
|
||||||
|
* pass the same details.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char pathname[MAXPGPATH];
|
||||||
|
pgoff_t size;
|
||||||
|
mode_t mode;
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
bool is_directory;
|
||||||
|
bool is_link;
|
||||||
|
char linktarget[MAXPGPATH];
|
||||||
|
} astreamer_member;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generally, each type of astreamer will define its own struct, but the
|
||||||
|
* first element should be 'astreamer base'. A astreamer that does not
|
||||||
|
* require any additional private data could use this structure directly.
|
||||||
|
*
|
||||||
|
* bbs_ops is a pointer to the astreamer_ops object which contains the
|
||||||
|
* function pointers appropriate to this type of astreamer.
|
||||||
|
*
|
||||||
|
* bbs_next is a pointer to the successor astreamer, for those types of
|
||||||
|
* astreamer which forward data to a successor. It need not be used and
|
||||||
|
* should be set to NULL when not relevant.
|
||||||
|
*
|
||||||
|
* bbs_buffer is a buffer for accumulating data for temporary storage. Each
|
||||||
|
* type of astreamer makes its own decisions about whether and how to use
|
||||||
|
* this buffer.
|
||||||
|
*/
|
||||||
|
struct astreamer
|
||||||
|
{
|
||||||
|
const astreamer_ops *bbs_ops;
|
||||||
|
astreamer *bbs_next;
|
||||||
|
StringInfoData bbs_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are three callbacks for a astreamer. The 'content' callback is
|
||||||
|
* called repeatedly, as described in the astreamer_archive_context comments.
|
||||||
|
* Then, the 'finalize' callback is called once at the end, to give the
|
||||||
|
* astreamer a chance to perform cleanup such as closing files. Finally,
|
||||||
|
* because this code is running in a frontend environment where, as of this
|
||||||
|
* writing, there are no memory contexts, the 'free' callback is called to
|
||||||
|
* release memory. These callbacks should always be invoked using the static
|
||||||
|
* inline functions defined below.
|
||||||
|
*/
|
||||||
|
struct astreamer_ops
|
||||||
|
{
|
||||||
|
void (*content) (astreamer *streamer, astreamer_member *member,
|
||||||
|
const char *data, int len,
|
||||||
|
astreamer_archive_context context);
|
||||||
|
void (*finalize) (astreamer *streamer);
|
||||||
|
void (*free) (astreamer *streamer);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Send some content to a astreamer. */
|
||||||
|
static inline void
|
||||||
|
astreamer_content(astreamer *streamer, astreamer_member *member,
|
||||||
|
const char *data, int len,
|
||||||
|
astreamer_archive_context context)
|
||||||
|
{
|
||||||
|
Assert(streamer != NULL);
|
||||||
|
streamer->bbs_ops->content(streamer, member, data, len, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize a astreamer. */
|
||||||
|
static inline void
|
||||||
|
astreamer_finalize(astreamer *streamer)
|
||||||
|
{
|
||||||
|
Assert(streamer != NULL);
|
||||||
|
streamer->bbs_ops->finalize(streamer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free a astreamer. */
|
||||||
|
static inline void
|
||||||
|
astreamer_free(astreamer *streamer)
|
||||||
|
{
|
||||||
|
Assert(streamer != NULL);
|
||||||
|
streamer->bbs_ops->free(streamer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a convenience method for use when implementing a astreamer; it is
|
||||||
|
* not for use by outside callers. It adds the amount of data specified by
|
||||||
|
* 'nbytes' to the astreamer's buffer and adjusts '*len' and '*data'
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
astreamer_buffer_bytes(astreamer *streamer, const char **data, int *len,
|
||||||
|
int nbytes)
|
||||||
|
{
|
||||||
|
Assert(nbytes <= *len);
|
||||||
|
|
||||||
|
appendBinaryStringInfo(&streamer->bbs_buffer, *data, nbytes);
|
||||||
|
*len -= nbytes;
|
||||||
|
*data += nbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a convenience method for use when implementing a astreamer; it is
|
||||||
|
* not for use by outsider callers. It attempts to add enough data to the
|
||||||
|
* astreamer's buffer to reach a length of target_bytes and adjusts '*len'
|
||||||
|
* and '*data' accordingly. It returns true if the target length has been
|
||||||
|
* reached and false otherwise.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
astreamer_buffer_until(astreamer *streamer, const char **data, int *len,
|
||||||
|
int target_bytes)
|
||||||
|
{
|
||||||
|
int buflen = streamer->bbs_buffer.len;
|
||||||
|
|
||||||
|
if (buflen >= target_bytes)
|
||||||
|
{
|
||||||
|
/* Target length already reached; nothing to do. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buflen + *len < target_bytes)
|
||||||
|
{
|
||||||
|
/* Not enough data to reach target length; buffer all of it. */
|
||||||
|
astreamer_buffer_bytes(streamer, data, len, *len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buffer just enough to reach the target length. */
|
||||||
|
astreamer_buffer_bytes(streamer, data, len, target_bytes - buflen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions for creating astreamer objects of various types. See the header
|
||||||
|
* comments for each of these functions for details.
|
||||||
|
*/
|
||||||
|
extern astreamer *astreamer_plain_writer_new(char *pathname, FILE *file);
|
||||||
|
extern astreamer *astreamer_gzip_writer_new(char *pathname, FILE *file,
|
||||||
|
pg_compress_specification *compress);
|
||||||
|
extern astreamer *astreamer_extractor_new(const char *basepath,
|
||||||
|
const char *(*link_map) (const char *),
|
||||||
|
void (*report_output_file) (const char *));
|
||||||
|
|
||||||
|
extern astreamer *astreamer_gzip_decompressor_new(astreamer *next);
|
||||||
|
extern astreamer *astreamer_lz4_compressor_new(astreamer *next,
|
||||||
|
pg_compress_specification *compress);
|
||||||
|
extern astreamer *astreamer_lz4_decompressor_new(astreamer *next);
|
||||||
|
extern astreamer *astreamer_zstd_compressor_new(astreamer *next,
|
||||||
|
pg_compress_specification *compress);
|
||||||
|
extern astreamer *astreamer_zstd_decompressor_new(astreamer *next);
|
||||||
|
extern astreamer *astreamer_tar_parser_new(astreamer *next);
|
||||||
|
extern astreamer *astreamer_tar_terminator_new(astreamer *next);
|
||||||
|
extern astreamer *astreamer_tar_archiver_new(astreamer *next);
|
||||||
|
|
||||||
|
extern astreamer *astreamer_recovery_injector_new(astreamer *next,
|
||||||
|
bool is_recovery_guc_supported,
|
||||||
|
PQExpBuffer recoveryconfcontents);
|
||||||
|
extern void astreamer_inject_file(astreamer *streamer, char *pathname,
|
||||||
|
char *data, int len);
|
||||||
|
|
||||||
|
#endif
|
@ -1,11 +1,11 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* bbstreamer_file.c
|
* astreamer_file.c
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* src/bin/pg_basebackup/bbstreamer_file.c
|
* src/bin/pg_basebackup/astreamer_file.c
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -13,60 +13,60 @@
|
|||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "bbstreamer.h"
|
#include "astreamer.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
|
|
||||||
typedef struct bbstreamer_plain_writer
|
typedef struct astreamer_plain_writer
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
char *pathname;
|
char *pathname;
|
||||||
FILE *file;
|
FILE *file;
|
||||||
bool should_close_file;
|
bool should_close_file;
|
||||||
} bbstreamer_plain_writer;
|
} astreamer_plain_writer;
|
||||||
|
|
||||||
typedef struct bbstreamer_extractor
|
typedef struct astreamer_extractor
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
char *basepath;
|
char *basepath;
|
||||||
const char *(*link_map) (const char *);
|
const char *(*link_map) (const char *);
|
||||||
void (*report_output_file) (const char *);
|
void (*report_output_file) (const char *);
|
||||||
char filename[MAXPGPATH];
|
char filename[MAXPGPATH];
|
||||||
FILE *file;
|
FILE *file;
|
||||||
} bbstreamer_extractor;
|
} astreamer_extractor;
|
||||||
|
|
||||||
static void bbstreamer_plain_writer_content(bbstreamer *streamer,
|
static void astreamer_plain_writer_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_plain_writer_finalize(bbstreamer *streamer);
|
static void astreamer_plain_writer_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_plain_writer_free(bbstreamer *streamer);
|
static void astreamer_plain_writer_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_plain_writer_ops = {
|
static const astreamer_ops astreamer_plain_writer_ops = {
|
||||||
.content = bbstreamer_plain_writer_content,
|
.content = astreamer_plain_writer_content,
|
||||||
.finalize = bbstreamer_plain_writer_finalize,
|
.finalize = astreamer_plain_writer_finalize,
|
||||||
.free = bbstreamer_plain_writer_free
|
.free = astreamer_plain_writer_free
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bbstreamer_extractor_content(bbstreamer *streamer,
|
static void astreamer_extractor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_extractor_finalize(bbstreamer *streamer);
|
static void astreamer_extractor_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_extractor_free(bbstreamer *streamer);
|
static void astreamer_extractor_free(astreamer *streamer);
|
||||||
static void extract_directory(const char *filename, mode_t mode);
|
static void extract_directory(const char *filename, mode_t mode);
|
||||||
static void extract_link(const char *filename, const char *linktarget);
|
static void extract_link(const char *filename, const char *linktarget);
|
||||||
static FILE *create_file_for_extract(const char *filename, mode_t mode);
|
static FILE *create_file_for_extract(const char *filename, mode_t mode);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_extractor_ops = {
|
static const astreamer_ops astreamer_extractor_ops = {
|
||||||
.content = bbstreamer_extractor_content,
|
.content = astreamer_extractor_content,
|
||||||
.finalize = bbstreamer_extractor_finalize,
|
.finalize = astreamer_extractor_finalize,
|
||||||
.free = bbstreamer_extractor_free
|
.free = astreamer_extractor_free
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that just writes data to a file.
|
* Create a astreamer that just writes data to a file.
|
||||||
*
|
*
|
||||||
* The caller must specify a pathname and may specify a file. The pathname is
|
* The caller must specify a pathname and may specify a file. The pathname is
|
||||||
* used for error-reporting purposes either way. If file is NULL, the pathname
|
* used for error-reporting purposes either way. If file is NULL, the pathname
|
||||||
@ -74,14 +74,14 @@ static const bbstreamer_ops bbstreamer_extractor_ops = {
|
|||||||
* for writing and closed when done. If file is not NULL, the data is written
|
* for writing and closed when done. If file is not NULL, the data is written
|
||||||
* there.
|
* there.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_plain_writer_new(char *pathname, FILE *file)
|
astreamer_plain_writer_new(char *pathname, FILE *file)
|
||||||
{
|
{
|
||||||
bbstreamer_plain_writer *streamer;
|
astreamer_plain_writer *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_plain_writer));
|
streamer = palloc0(sizeof(astreamer_plain_writer));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_plain_writer_ops;
|
&astreamer_plain_writer_ops;
|
||||||
|
|
||||||
streamer->pathname = pstrdup(pathname);
|
streamer->pathname = pstrdup(pathname);
|
||||||
streamer->file = file;
|
streamer->file = file;
|
||||||
@ -101,13 +101,13 @@ bbstreamer_plain_writer_new(char *pathname, FILE *file)
|
|||||||
* Write archive content to file.
|
* Write archive content to file.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_plain_writer_content(bbstreamer *streamer,
|
astreamer_plain_writer_content(astreamer *streamer,
|
||||||
bbstreamer_member *member, const char *data,
|
astreamer_member *member, const char *data,
|
||||||
int len, bbstreamer_archive_context context)
|
int len, astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_plain_writer *mystreamer;
|
astreamer_plain_writer *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_plain_writer *) streamer;
|
mystreamer = (astreamer_plain_writer *) streamer;
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
@ -128,11 +128,11 @@ bbstreamer_plain_writer_content(bbstreamer *streamer,
|
|||||||
* the file if we opened it, but not if the caller provided it.
|
* the file if we opened it, but not if the caller provided it.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_plain_writer_finalize(bbstreamer *streamer)
|
astreamer_plain_writer_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_plain_writer *mystreamer;
|
astreamer_plain_writer *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_plain_writer *) streamer;
|
mystreamer = (astreamer_plain_writer *) streamer;
|
||||||
|
|
||||||
if (mystreamer->should_close_file && fclose(mystreamer->file) != 0)
|
if (mystreamer->should_close_file && fclose(mystreamer->file) != 0)
|
||||||
pg_fatal("could not close file \"%s\": %m",
|
pg_fatal("could not close file \"%s\": %m",
|
||||||
@ -143,14 +143,14 @@ bbstreamer_plain_writer_finalize(bbstreamer *streamer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory associated with this bbstreamer.
|
* Free memory associated with this astreamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_plain_writer_free(bbstreamer *streamer)
|
astreamer_plain_writer_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_plain_writer *mystreamer;
|
astreamer_plain_writer *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_plain_writer *) streamer;
|
mystreamer = (astreamer_plain_writer *) streamer;
|
||||||
|
|
||||||
Assert(!mystreamer->should_close_file);
|
Assert(!mystreamer->should_close_file);
|
||||||
Assert(mystreamer->base.bbs_next == NULL);
|
Assert(mystreamer->base.bbs_next == NULL);
|
||||||
@ -160,13 +160,13 @@ bbstreamer_plain_writer_free(bbstreamer *streamer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that extracts an archive.
|
* Create a astreamer that extracts an archive.
|
||||||
*
|
*
|
||||||
* All pathnames in the archive are interpreted relative to basepath.
|
* All pathnames in the archive are interpreted relative to basepath.
|
||||||
*
|
*
|
||||||
* Unlike e.g. bbstreamer_plain_writer_new() we can't do anything useful here
|
* Unlike e.g. astreamer_plain_writer_new() we can't do anything useful here
|
||||||
* with untyped chunks; we need typed chunks which follow the rules described
|
* with untyped chunks; we need typed chunks which follow the rules described
|
||||||
* in bbstreamer.h. Assuming we have that, we don't need to worry about the
|
* in astreamer.h. Assuming we have that, we don't need to worry about the
|
||||||
* original archive format; it's enough to just look at the member information
|
* original archive format; it's enough to just look at the member information
|
||||||
* provided and write to the corresponding file.
|
* provided and write to the corresponding file.
|
||||||
*
|
*
|
||||||
@ -179,16 +179,16 @@ bbstreamer_plain_writer_free(bbstreamer *streamer)
|
|||||||
* new output file. The pathname to that file is passed as an argument. If
|
* new output file. The pathname to that file is passed as an argument. If
|
||||||
* NULL, the call is skipped.
|
* NULL, the call is skipped.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_extractor_new(const char *basepath,
|
astreamer_extractor_new(const char *basepath,
|
||||||
const char *(*link_map) (const char *),
|
const char *(*link_map) (const char *),
|
||||||
void (*report_output_file) (const char *))
|
void (*report_output_file) (const char *))
|
||||||
{
|
{
|
||||||
bbstreamer_extractor *streamer;
|
astreamer_extractor *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_extractor));
|
streamer = palloc0(sizeof(astreamer_extractor));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_extractor_ops;
|
&astreamer_extractor_ops;
|
||||||
streamer->basepath = pstrdup(basepath);
|
streamer->basepath = pstrdup(basepath);
|
||||||
streamer->link_map = link_map;
|
streamer->link_map = link_map;
|
||||||
streamer->report_output_file = report_output_file;
|
streamer->report_output_file = report_output_file;
|
||||||
@ -200,19 +200,19 @@ bbstreamer_extractor_new(const char *basepath,
|
|||||||
* Extract archive contents to the filesystem.
|
* Extract archive contents to the filesystem.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
|
astreamer_extractor_content(astreamer *streamer, astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_extractor *mystreamer = (bbstreamer_extractor *) streamer;
|
astreamer_extractor *mystreamer = (astreamer_extractor *) streamer;
|
||||||
int fnamelen;
|
int fnamelen;
|
||||||
|
|
||||||
Assert(member != NULL || context == BBSTREAMER_ARCHIVE_TRAILER);
|
Assert(member != NULL || context == ASTREAMER_ARCHIVE_TRAILER);
|
||||||
Assert(context != BBSTREAMER_UNKNOWN);
|
Assert(context != ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
switch (context)
|
switch (context)
|
||||||
{
|
{
|
||||||
case BBSTREAMER_MEMBER_HEADER:
|
case ASTREAMER_MEMBER_HEADER:
|
||||||
Assert(mystreamer->file == NULL);
|
Assert(mystreamer->file == NULL);
|
||||||
|
|
||||||
/* Prepend basepath. */
|
/* Prepend basepath. */
|
||||||
@ -245,7 +245,7 @@ bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
|
|||||||
mystreamer->report_output_file(mystreamer->filename);
|
mystreamer->report_output_file(mystreamer->filename);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_MEMBER_CONTENTS:
|
case ASTREAMER_MEMBER_CONTENTS:
|
||||||
if (mystreamer->file == NULL)
|
if (mystreamer->file == NULL)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -260,14 +260,14 @@ bbstreamer_extractor_content(bbstreamer *streamer, bbstreamer_member *member,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_MEMBER_TRAILER:
|
case ASTREAMER_MEMBER_TRAILER:
|
||||||
if (mystreamer->file == NULL)
|
if (mystreamer->file == NULL)
|
||||||
break;
|
break;
|
||||||
fclose(mystreamer->file);
|
fclose(mystreamer->file);
|
||||||
mystreamer->file = NULL;
|
mystreamer->file = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_ARCHIVE_TRAILER:
|
case ASTREAMER_ARCHIVE_TRAILER:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -375,10 +375,10 @@ create_file_for_extract(const char *filename, mode_t mode)
|
|||||||
* There's nothing to do here but sanity checking.
|
* There's nothing to do here but sanity checking.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_extractor_finalize(bbstreamer *streamer)
|
astreamer_extractor_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_extractor *mystreamer PG_USED_FOR_ASSERTS_ONLY
|
astreamer_extractor *mystreamer PG_USED_FOR_ASSERTS_ONLY
|
||||||
= (bbstreamer_extractor *) streamer;
|
= (astreamer_extractor *) streamer;
|
||||||
|
|
||||||
Assert(mystreamer->file == NULL);
|
Assert(mystreamer->file == NULL);
|
||||||
}
|
}
|
||||||
@ -387,9 +387,9 @@ bbstreamer_extractor_finalize(bbstreamer *streamer)
|
|||||||
* Free memory.
|
* Free memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_extractor_free(bbstreamer *streamer)
|
astreamer_extractor_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_extractor *mystreamer = (bbstreamer_extractor *) streamer;
|
astreamer_extractor *mystreamer = (astreamer_extractor *) streamer;
|
||||||
|
|
||||||
pfree(mystreamer->basepath);
|
pfree(mystreamer->basepath);
|
||||||
pfree(mystreamer);
|
pfree(mystreamer);
|
@ -1,11 +1,11 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* bbstreamer_gzip.c
|
* astreamer_gzip.c
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* src/bin/pg_basebackup/bbstreamer_gzip.c
|
* src/bin/pg_basebackup/astreamer_gzip.c
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -17,74 +17,74 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "bbstreamer.h"
|
#include "astreamer.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
typedef struct bbstreamer_gzip_writer
|
typedef struct astreamer_gzip_writer
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
char *pathname;
|
char *pathname;
|
||||||
gzFile gzfile;
|
gzFile gzfile;
|
||||||
} bbstreamer_gzip_writer;
|
} astreamer_gzip_writer;
|
||||||
|
|
||||||
typedef struct bbstreamer_gzip_decompressor
|
typedef struct astreamer_gzip_decompressor
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
z_stream zstream;
|
z_stream zstream;
|
||||||
size_t bytes_written;
|
size_t bytes_written;
|
||||||
} bbstreamer_gzip_decompressor;
|
} astreamer_gzip_decompressor;
|
||||||
|
|
||||||
static void bbstreamer_gzip_writer_content(bbstreamer *streamer,
|
static void astreamer_gzip_writer_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_gzip_writer_finalize(bbstreamer *streamer);
|
static void astreamer_gzip_writer_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_gzip_writer_free(bbstreamer *streamer);
|
static void astreamer_gzip_writer_free(astreamer *streamer);
|
||||||
static const char *get_gz_error(gzFile gzf);
|
static const char *get_gz_error(gzFile gzf);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_gzip_writer_ops = {
|
static const astreamer_ops astreamer_gzip_writer_ops = {
|
||||||
.content = bbstreamer_gzip_writer_content,
|
.content = astreamer_gzip_writer_content,
|
||||||
.finalize = bbstreamer_gzip_writer_finalize,
|
.finalize = astreamer_gzip_writer_finalize,
|
||||||
.free = bbstreamer_gzip_writer_free
|
.free = astreamer_gzip_writer_free
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bbstreamer_gzip_decompressor_content(bbstreamer *streamer,
|
static void astreamer_gzip_decompressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_gzip_decompressor_finalize(bbstreamer *streamer);
|
static void astreamer_gzip_decompressor_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_gzip_decompressor_free(bbstreamer *streamer);
|
static void astreamer_gzip_decompressor_free(astreamer *streamer);
|
||||||
static void *gzip_palloc(void *opaque, unsigned items, unsigned size);
|
static void *gzip_palloc(void *opaque, unsigned items, unsigned size);
|
||||||
static void gzip_pfree(void *opaque, void *address);
|
static void gzip_pfree(void *opaque, void *address);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_gzip_decompressor_ops = {
|
static const astreamer_ops astreamer_gzip_decompressor_ops = {
|
||||||
.content = bbstreamer_gzip_decompressor_content,
|
.content = astreamer_gzip_decompressor_content,
|
||||||
.finalize = bbstreamer_gzip_decompressor_finalize,
|
.finalize = astreamer_gzip_decompressor_finalize,
|
||||||
.free = bbstreamer_gzip_decompressor_free
|
.free = astreamer_gzip_decompressor_free
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that just compresses data using gzip, and then writes
|
* Create a astreamer that just compresses data using gzip, and then writes
|
||||||
* it to a file.
|
* it to a file.
|
||||||
*
|
*
|
||||||
* As in the case of bbstreamer_plain_writer_new, pathname is always used
|
* As in the case of astreamer_plain_writer_new, pathname is always used
|
||||||
* for error reporting purposes; if file is NULL, it is also the opened and
|
* for error reporting purposes; if file is NULL, it is also the opened and
|
||||||
* closed so that the data may be written there.
|
* closed so that the data may be written there.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_gzip_writer_new(char *pathname, FILE *file,
|
astreamer_gzip_writer_new(char *pathname, FILE *file,
|
||||||
pg_compress_specification *compress)
|
pg_compress_specification *compress)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
bbstreamer_gzip_writer *streamer;
|
astreamer_gzip_writer *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_gzip_writer));
|
streamer = palloc0(sizeof(astreamer_gzip_writer));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_gzip_writer_ops;
|
&astreamer_gzip_writer_ops;
|
||||||
|
|
||||||
streamer->pathname = pstrdup(pathname);
|
streamer->pathname = pstrdup(pathname);
|
||||||
|
|
||||||
@ -123,13 +123,13 @@ bbstreamer_gzip_writer_new(char *pathname, FILE *file,
|
|||||||
* Write archive content to gzip file.
|
* Write archive content to gzip file.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_gzip_writer_content(bbstreamer *streamer,
|
astreamer_gzip_writer_content(astreamer *streamer,
|
||||||
bbstreamer_member *member, const char *data,
|
astreamer_member *member, const char *data,
|
||||||
int len, bbstreamer_archive_context context)
|
int len, astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_gzip_writer *mystreamer;
|
astreamer_gzip_writer *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_gzip_writer *) streamer;
|
mystreamer = (astreamer_gzip_writer *) streamer;
|
||||||
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
@ -151,16 +151,16 @@ bbstreamer_gzip_writer_content(bbstreamer *streamer,
|
|||||||
*
|
*
|
||||||
* It makes no difference whether we opened the file or the caller did it,
|
* It makes no difference whether we opened the file or the caller did it,
|
||||||
* because libz provides no way of avoiding a close on the underlying file
|
* because libz provides no way of avoiding a close on the underlying file
|
||||||
* handle. Notice, however, that bbstreamer_gzip_writer_new() uses dup() to
|
* handle. Notice, however, that astreamer_gzip_writer_new() uses dup() to
|
||||||
* work around this issue, so that the behavior from the caller's viewpoint
|
* work around this issue, so that the behavior from the caller's viewpoint
|
||||||
* is the same as for bbstreamer_plain_writer.
|
* is the same as for astreamer_plain_writer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_gzip_writer_finalize(bbstreamer *streamer)
|
astreamer_gzip_writer_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_gzip_writer *mystreamer;
|
astreamer_gzip_writer *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_gzip_writer *) streamer;
|
mystreamer = (astreamer_gzip_writer *) streamer;
|
||||||
|
|
||||||
errno = 0; /* in case gzclose() doesn't set it */
|
errno = 0; /* in case gzclose() doesn't set it */
|
||||||
if (gzclose(mystreamer->gzfile) != 0)
|
if (gzclose(mystreamer->gzfile) != 0)
|
||||||
@ -171,14 +171,14 @@ bbstreamer_gzip_writer_finalize(bbstreamer *streamer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory associated with this bbstreamer.
|
* Free memory associated with this astreamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_gzip_writer_free(bbstreamer *streamer)
|
astreamer_gzip_writer_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_gzip_writer *mystreamer;
|
astreamer_gzip_writer *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_gzip_writer *) streamer;
|
mystreamer = (astreamer_gzip_writer *) streamer;
|
||||||
|
|
||||||
Assert(mystreamer->base.bbs_next == NULL);
|
Assert(mystreamer->base.bbs_next == NULL);
|
||||||
Assert(mystreamer->gzfile == NULL);
|
Assert(mystreamer->gzfile == NULL);
|
||||||
@ -208,18 +208,18 @@ get_gz_error(gzFile gzf)
|
|||||||
* Create a new base backup streamer that performs decompression of gzip
|
* Create a new base backup streamer that performs decompression of gzip
|
||||||
* compressed blocks.
|
* compressed blocks.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_gzip_decompressor_new(bbstreamer *next)
|
astreamer_gzip_decompressor_new(astreamer *next)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
bbstreamer_gzip_decompressor *streamer;
|
astreamer_gzip_decompressor *streamer;
|
||||||
z_stream *zs;
|
z_stream *zs;
|
||||||
|
|
||||||
Assert(next != NULL);
|
Assert(next != NULL);
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_gzip_decompressor));
|
streamer = palloc0(sizeof(astreamer_gzip_decompressor));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_gzip_decompressor_ops;
|
&astreamer_gzip_decompressor_ops;
|
||||||
|
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
initStringInfo(&streamer->base.bbs_buffer);
|
initStringInfo(&streamer->base.bbs_buffer);
|
||||||
@ -258,15 +258,15 @@ bbstreamer_gzip_decompressor_new(bbstreamer *next)
|
|||||||
* to the next streamer.
|
* to the next streamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_gzip_decompressor_content(bbstreamer *streamer,
|
astreamer_gzip_decompressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_gzip_decompressor *mystreamer;
|
astreamer_gzip_decompressor *mystreamer;
|
||||||
z_stream *zs;
|
z_stream *zs;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_gzip_decompressor *) streamer;
|
mystreamer = (astreamer_gzip_decompressor *) streamer;
|
||||||
|
|
||||||
zs = &mystreamer->zstream;
|
zs = &mystreamer->zstream;
|
||||||
zs->next_in = (const uint8 *) data;
|
zs->next_in = (const uint8 *) data;
|
||||||
@ -301,7 +301,7 @@ bbstreamer_gzip_decompressor_content(bbstreamer *streamer,
|
|||||||
/* If output buffer is full then pass data to next streamer */
|
/* If output buffer is full then pass data to next streamer */
|
||||||
if (mystreamer->bytes_written >= mystreamer->base.bbs_buffer.maxlen)
|
if (mystreamer->bytes_written >= mystreamer->base.bbs_buffer.maxlen)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->base.bbs_buffer.maxlen, context);
|
mystreamer->base.bbs_buffer.maxlen, context);
|
||||||
mystreamer->bytes_written = 0;
|
mystreamer->bytes_written = 0;
|
||||||
@ -313,31 +313,31 @@ bbstreamer_gzip_decompressor_content(bbstreamer *streamer,
|
|||||||
* End-of-stream processing.
|
* End-of-stream processing.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_gzip_decompressor_finalize(bbstreamer *streamer)
|
astreamer_gzip_decompressor_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_gzip_decompressor *mystreamer;
|
astreamer_gzip_decompressor *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_gzip_decompressor *) streamer;
|
mystreamer = (astreamer_gzip_decompressor *) streamer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of the stream, if there is some pending data in output buffers then
|
* End of the stream, if there is some pending data in output buffers then
|
||||||
* we must forward it to next streamer.
|
* we must forward it to next streamer.
|
||||||
*/
|
*/
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->base.bbs_buffer.maxlen,
|
mystreamer->base.bbs_buffer.maxlen,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
bbstreamer_finalize(mystreamer->base.bbs_next);
|
astreamer_finalize(mystreamer->base.bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory.
|
* Free memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_gzip_decompressor_free(bbstreamer *streamer)
|
astreamer_gzip_decompressor_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
pfree(streamer->bbs_buffer.data);
|
pfree(streamer->bbs_buffer.data);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
||||||
}
|
}
|
@ -1,51 +1,51 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* bbstreamer_inject.c
|
* astreamer_inject.c
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* src/bin/pg_basebackup/bbstreamer_inject.c
|
* src/bin/pg_basebackup/astreamer_inject.c
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
#include "bbstreamer.h"
|
#include "astreamer.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
|
|
||||||
typedef struct bbstreamer_recovery_injector
|
typedef struct astreamer_recovery_injector
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
bool skip_file;
|
bool skip_file;
|
||||||
bool is_recovery_guc_supported;
|
bool is_recovery_guc_supported;
|
||||||
bool is_postgresql_auto_conf;
|
bool is_postgresql_auto_conf;
|
||||||
bool found_postgresql_auto_conf;
|
bool found_postgresql_auto_conf;
|
||||||
PQExpBuffer recoveryconfcontents;
|
PQExpBuffer recoveryconfcontents;
|
||||||
bbstreamer_member member;
|
astreamer_member member;
|
||||||
} bbstreamer_recovery_injector;
|
} astreamer_recovery_injector;
|
||||||
|
|
||||||
static void bbstreamer_recovery_injector_content(bbstreamer *streamer,
|
static void astreamer_recovery_injector_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_recovery_injector_finalize(bbstreamer *streamer);
|
static void astreamer_recovery_injector_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_recovery_injector_free(bbstreamer *streamer);
|
static void astreamer_recovery_injector_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_recovery_injector_ops = {
|
static const astreamer_ops astreamer_recovery_injector_ops = {
|
||||||
.content = bbstreamer_recovery_injector_content,
|
.content = astreamer_recovery_injector_content,
|
||||||
.finalize = bbstreamer_recovery_injector_finalize,
|
.finalize = astreamer_recovery_injector_finalize,
|
||||||
.free = bbstreamer_recovery_injector_free
|
.free = astreamer_recovery_injector_free
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that can edit recoverydata into an archive stream.
|
* Create a astreamer that can edit recoverydata into an archive stream.
|
||||||
*
|
*
|
||||||
* The input should be a series of typed chunks (not BBSTREAMER_UNKNOWN) as
|
* The input should be a series of typed chunks (not ASTREAMER_UNKNOWN) as
|
||||||
* per the conventions described in bbstreamer.h; the chunks forwarded to
|
* per the conventions described in astreamer.h; the chunks forwarded to
|
||||||
* the next bbstreamer will be similarly typed, but the
|
* the next astreamer will be similarly typed, but the
|
||||||
* BBSTREAMER_MEMBER_HEADER chunks may be zero-length in cases where we've
|
* ASTREAMER_MEMBER_HEADER chunks may be zero-length in cases where we've
|
||||||
* edited the archive stream.
|
* edited the archive stream.
|
||||||
*
|
*
|
||||||
* Our goal is to do one of the following three things with the content passed
|
* Our goal is to do one of the following three things with the content passed
|
||||||
@ -61,16 +61,16 @@ static const bbstreamer_ops bbstreamer_recovery_injector_ops = {
|
|||||||
* zero-length standby.signal file, dropping any file with that name from
|
* zero-length standby.signal file, dropping any file with that name from
|
||||||
* the archive.
|
* the archive.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_recovery_injector_new(bbstreamer *next,
|
astreamer_recovery_injector_new(astreamer *next,
|
||||||
bool is_recovery_guc_supported,
|
bool is_recovery_guc_supported,
|
||||||
PQExpBuffer recoveryconfcontents)
|
PQExpBuffer recoveryconfcontents)
|
||||||
{
|
{
|
||||||
bbstreamer_recovery_injector *streamer;
|
astreamer_recovery_injector *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_recovery_injector));
|
streamer = palloc0(sizeof(astreamer_recovery_injector));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_recovery_injector_ops;
|
&astreamer_recovery_injector_ops;
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
streamer->is_recovery_guc_supported = is_recovery_guc_supported;
|
streamer->is_recovery_guc_supported = is_recovery_guc_supported;
|
||||||
streamer->recoveryconfcontents = recoveryconfcontents;
|
streamer->recoveryconfcontents = recoveryconfcontents;
|
||||||
@ -82,21 +82,21 @@ bbstreamer_recovery_injector_new(bbstreamer *next,
|
|||||||
* Handle each chunk of tar content while injecting recovery configuration.
|
* Handle each chunk of tar content while injecting recovery configuration.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_recovery_injector_content(bbstreamer *streamer,
|
astreamer_recovery_injector_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_recovery_injector *mystreamer;
|
astreamer_recovery_injector *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_recovery_injector *) streamer;
|
mystreamer = (astreamer_recovery_injector *) streamer;
|
||||||
Assert(member != NULL || context == BBSTREAMER_ARCHIVE_TRAILER);
|
Assert(member != NULL || context == ASTREAMER_ARCHIVE_TRAILER);
|
||||||
|
|
||||||
switch (context)
|
switch (context)
|
||||||
{
|
{
|
||||||
case BBSTREAMER_MEMBER_HEADER:
|
case ASTREAMER_MEMBER_HEADER:
|
||||||
/* Must copy provided data so we have the option to modify it. */
|
/* Must copy provided data so we have the option to modify it. */
|
||||||
memcpy(&mystreamer->member, member, sizeof(bbstreamer_member));
|
memcpy(&mystreamer->member, member, sizeof(astreamer_member));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On v12+, skip standby.signal and edit postgresql.auto.conf; on
|
* On v12+, skip standby.signal and edit postgresql.auto.conf; on
|
||||||
@ -119,8 +119,8 @@ bbstreamer_recovery_injector_content(bbstreamer *streamer,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Zap data and len because the archive header is no
|
* Zap data and len because the archive header is no
|
||||||
* longer valid; some subsequent bbstreamer must
|
* longer valid; some subsequent astreamer must regenerate
|
||||||
* regenerate it if it's necessary.
|
* it if it's necessary.
|
||||||
*/
|
*/
|
||||||
data = NULL;
|
data = NULL;
|
||||||
len = 0;
|
len = 0;
|
||||||
@ -135,26 +135,26 @@ bbstreamer_recovery_injector_content(bbstreamer *streamer,
|
|||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_MEMBER_CONTENTS:
|
case ASTREAMER_MEMBER_CONTENTS:
|
||||||
/* Do not forward if the file is to be skipped. */
|
/* Do not forward if the file is to be skipped. */
|
||||||
if (mystreamer->skip_file)
|
if (mystreamer->skip_file)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_MEMBER_TRAILER:
|
case ASTREAMER_MEMBER_TRAILER:
|
||||||
/* Do not forward it the file is to be skipped. */
|
/* Do not forward it the file is to be skipped. */
|
||||||
if (mystreamer->skip_file)
|
if (mystreamer->skip_file)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Append provided content to whatever we already sent. */
|
/* Append provided content to whatever we already sent. */
|
||||||
if (mystreamer->is_postgresql_auto_conf)
|
if (mystreamer->is_postgresql_auto_conf)
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
mystreamer->recoveryconfcontents->data,
|
mystreamer->recoveryconfcontents->data,
|
||||||
mystreamer->recoveryconfcontents->len,
|
mystreamer->recoveryconfcontents->len,
|
||||||
BBSTREAMER_MEMBER_CONTENTS);
|
ASTREAMER_MEMBER_CONTENTS);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_ARCHIVE_TRAILER:
|
case ASTREAMER_ARCHIVE_TRAILER:
|
||||||
if (mystreamer->is_recovery_guc_supported)
|
if (mystreamer->is_recovery_guc_supported)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -163,19 +163,19 @@ bbstreamer_recovery_injector_content(bbstreamer *streamer,
|
|||||||
* member now.
|
* member now.
|
||||||
*/
|
*/
|
||||||
if (!mystreamer->found_postgresql_auto_conf)
|
if (!mystreamer->found_postgresql_auto_conf)
|
||||||
bbstreamer_inject_file(mystreamer->base.bbs_next,
|
astreamer_inject_file(mystreamer->base.bbs_next,
|
||||||
"postgresql.auto.conf",
|
"postgresql.auto.conf",
|
||||||
mystreamer->recoveryconfcontents->data,
|
mystreamer->recoveryconfcontents->data,
|
||||||
mystreamer->recoveryconfcontents->len);
|
mystreamer->recoveryconfcontents->len);
|
||||||
|
|
||||||
/* Inject empty standby.signal file. */
|
/* Inject empty standby.signal file. */
|
||||||
bbstreamer_inject_file(mystreamer->base.bbs_next,
|
astreamer_inject_file(mystreamer->base.bbs_next,
|
||||||
"standby.signal", "", 0);
|
"standby.signal", "", 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Inject recovery.conf file with specified contents. */
|
/* Inject recovery.conf file with specified contents. */
|
||||||
bbstreamer_inject_file(mystreamer->base.bbs_next,
|
astreamer_inject_file(mystreamer->base.bbs_next,
|
||||||
"recovery.conf",
|
"recovery.conf",
|
||||||
mystreamer->recoveryconfcontents->data,
|
mystreamer->recoveryconfcontents->data,
|
||||||
mystreamer->recoveryconfcontents->len);
|
mystreamer->recoveryconfcontents->len);
|
||||||
@ -189,26 +189,26 @@ bbstreamer_recovery_injector_content(bbstreamer *streamer,
|
|||||||
pg_fatal("unexpected state while injecting recovery settings");
|
pg_fatal("unexpected state while injecting recovery settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, &mystreamer->member,
|
astreamer_content(mystreamer->base.bbs_next, &mystreamer->member,
|
||||||
data, len, context);
|
data, len, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End-of-stream processing for this bbstreamer.
|
* End-of-stream processing for this astreamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_recovery_injector_finalize(bbstreamer *streamer)
|
astreamer_recovery_injector_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_finalize(streamer->bbs_next);
|
astreamer_finalize(streamer->bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory associated with this bbstreamer.
|
* Free memory associated with this astreamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_recovery_injector_free(bbstreamer *streamer)
|
astreamer_recovery_injector_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,10 +216,10 @@ bbstreamer_recovery_injector_free(bbstreamer *streamer)
|
|||||||
* Inject a member into the archive with specified contents.
|
* Inject a member into the archive with specified contents.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
bbstreamer_inject_file(bbstreamer *streamer, char *pathname, char *data,
|
astreamer_inject_file(astreamer *streamer, char *pathname, char *data,
|
||||||
int len)
|
int len)
|
||||||
{
|
{
|
||||||
bbstreamer_member member;
|
astreamer_member member;
|
||||||
|
|
||||||
strlcpy(member.pathname, pathname, MAXPGPATH);
|
strlcpy(member.pathname, pathname, MAXPGPATH);
|
||||||
member.size = len;
|
member.size = len;
|
||||||
@ -238,12 +238,12 @@ bbstreamer_inject_file(bbstreamer *streamer, char *pathname, char *data,
|
|||||||
/*
|
/*
|
||||||
* We don't know here how to generate valid member headers and trailers
|
* We don't know here how to generate valid member headers and trailers
|
||||||
* for the archiving format in use, so if those are needed, some successor
|
* for the archiving format in use, so if those are needed, some successor
|
||||||
* bbstreamer will have to generate them using the data from 'member'.
|
* astreamer will have to generate them using the data from 'member'.
|
||||||
*/
|
*/
|
||||||
bbstreamer_content(streamer, &member, NULL, 0,
|
astreamer_content(streamer, &member, NULL, 0,
|
||||||
BBSTREAMER_MEMBER_HEADER);
|
ASTREAMER_MEMBER_HEADER);
|
||||||
bbstreamer_content(streamer, &member, data, len,
|
astreamer_content(streamer, &member, data, len,
|
||||||
BBSTREAMER_MEMBER_CONTENTS);
|
ASTREAMER_MEMBER_CONTENTS);
|
||||||
bbstreamer_content(streamer, &member, NULL, 0,
|
astreamer_content(streamer, &member, NULL, 0,
|
||||||
BBSTREAMER_MEMBER_TRAILER);
|
ASTREAMER_MEMBER_TRAILER);
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* bbstreamer_lz4.c
|
* astreamer_lz4.c
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* src/bin/pg_basebackup/bbstreamer_lz4.c
|
* src/bin/pg_basebackup/astreamer_lz4.c
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -17,15 +17,15 @@
|
|||||||
#include <lz4frame.h>
|
#include <lz4frame.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "bbstreamer.h"
|
#include "astreamer.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/string.h"
|
#include "common/string.h"
|
||||||
|
|
||||||
#ifdef USE_LZ4
|
#ifdef USE_LZ4
|
||||||
typedef struct bbstreamer_lz4_frame
|
typedef struct astreamer_lz4_frame
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
|
|
||||||
LZ4F_compressionContext_t cctx;
|
LZ4F_compressionContext_t cctx;
|
||||||
LZ4F_decompressionContext_t dctx;
|
LZ4F_decompressionContext_t dctx;
|
||||||
@ -33,32 +33,32 @@ typedef struct bbstreamer_lz4_frame
|
|||||||
|
|
||||||
size_t bytes_written;
|
size_t bytes_written;
|
||||||
bool header_written;
|
bool header_written;
|
||||||
} bbstreamer_lz4_frame;
|
} astreamer_lz4_frame;
|
||||||
|
|
||||||
static void bbstreamer_lz4_compressor_content(bbstreamer *streamer,
|
static void astreamer_lz4_compressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_lz4_compressor_finalize(bbstreamer *streamer);
|
static void astreamer_lz4_compressor_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_lz4_compressor_free(bbstreamer *streamer);
|
static void astreamer_lz4_compressor_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_lz4_compressor_ops = {
|
static const astreamer_ops astreamer_lz4_compressor_ops = {
|
||||||
.content = bbstreamer_lz4_compressor_content,
|
.content = astreamer_lz4_compressor_content,
|
||||||
.finalize = bbstreamer_lz4_compressor_finalize,
|
.finalize = astreamer_lz4_compressor_finalize,
|
||||||
.free = bbstreamer_lz4_compressor_free
|
.free = astreamer_lz4_compressor_free
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bbstreamer_lz4_decompressor_content(bbstreamer *streamer,
|
static void astreamer_lz4_decompressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_lz4_decompressor_finalize(bbstreamer *streamer);
|
static void astreamer_lz4_decompressor_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_lz4_decompressor_free(bbstreamer *streamer);
|
static void astreamer_lz4_decompressor_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_lz4_decompressor_ops = {
|
static const astreamer_ops astreamer_lz4_decompressor_ops = {
|
||||||
.content = bbstreamer_lz4_decompressor_content,
|
.content = astreamer_lz4_decompressor_content,
|
||||||
.finalize = bbstreamer_lz4_decompressor_finalize,
|
.finalize = astreamer_lz4_decompressor_finalize,
|
||||||
.free = bbstreamer_lz4_decompressor_free
|
.free = astreamer_lz4_decompressor_free
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -66,19 +66,19 @@ static const bbstreamer_ops bbstreamer_lz4_decompressor_ops = {
|
|||||||
* Create a new base backup streamer that performs lz4 compression of tar
|
* Create a new base backup streamer that performs lz4 compression of tar
|
||||||
* blocks.
|
* blocks.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_lz4_compressor_new(bbstreamer *next, pg_compress_specification *compress)
|
astreamer_lz4_compressor_new(astreamer *next, pg_compress_specification *compress)
|
||||||
{
|
{
|
||||||
#ifdef USE_LZ4
|
#ifdef USE_LZ4
|
||||||
bbstreamer_lz4_frame *streamer;
|
astreamer_lz4_frame *streamer;
|
||||||
LZ4F_errorCode_t ctxError;
|
LZ4F_errorCode_t ctxError;
|
||||||
LZ4F_preferences_t *prefs;
|
LZ4F_preferences_t *prefs;
|
||||||
|
|
||||||
Assert(next != NULL);
|
Assert(next != NULL);
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_lz4_frame));
|
streamer = palloc0(sizeof(astreamer_lz4_frame));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_lz4_compressor_ops;
|
&astreamer_lz4_compressor_ops;
|
||||||
|
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
initStringInfo(&streamer->base.bbs_buffer);
|
initStringInfo(&streamer->base.bbs_buffer);
|
||||||
@ -113,19 +113,19 @@ bbstreamer_lz4_compressor_new(bbstreamer *next, pg_compress_specification *compr
|
|||||||
* of output buffer to next streamer and empty the buffer.
|
* of output buffer to next streamer and empty the buffer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_lz4_compressor_content(bbstreamer *streamer,
|
astreamer_lz4_compressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_lz4_frame *mystreamer;
|
astreamer_lz4_frame *mystreamer;
|
||||||
uint8 *next_in,
|
uint8 *next_in,
|
||||||
*next_out;
|
*next_out;
|
||||||
size_t out_bound,
|
size_t out_bound,
|
||||||
compressed_size,
|
compressed_size,
|
||||||
avail_out;
|
avail_out;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_lz4_frame *) streamer;
|
mystreamer = (astreamer_lz4_frame *) streamer;
|
||||||
next_in = (uint8 *) data;
|
next_in = (uint8 *) data;
|
||||||
|
|
||||||
/* Write header before processing the first input chunk. */
|
/* Write header before processing the first input chunk. */
|
||||||
@ -159,7 +159,7 @@ bbstreamer_lz4_compressor_content(bbstreamer *streamer,
|
|||||||
out_bound = LZ4F_compressBound(len, &mystreamer->prefs);
|
out_bound = LZ4F_compressBound(len, &mystreamer->prefs);
|
||||||
if (avail_out < out_bound)
|
if (avail_out < out_bound)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->bytes_written,
|
mystreamer->bytes_written,
|
||||||
context);
|
context);
|
||||||
@ -196,25 +196,25 @@ bbstreamer_lz4_compressor_content(bbstreamer *streamer,
|
|||||||
* End-of-stream processing.
|
* End-of-stream processing.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_lz4_compressor_finalize(bbstreamer *streamer)
|
astreamer_lz4_compressor_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_lz4_frame *mystreamer;
|
astreamer_lz4_frame *mystreamer;
|
||||||
uint8 *next_out;
|
uint8 *next_out;
|
||||||
size_t footer_bound,
|
size_t footer_bound,
|
||||||
compressed_size,
|
compressed_size,
|
||||||
avail_out;
|
avail_out;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_lz4_frame *) streamer;
|
mystreamer = (astreamer_lz4_frame *) streamer;
|
||||||
|
|
||||||
/* Find out the footer bound and update the output buffer. */
|
/* Find out the footer bound and update the output buffer. */
|
||||||
footer_bound = LZ4F_compressBound(0, &mystreamer->prefs);
|
footer_bound = LZ4F_compressBound(0, &mystreamer->prefs);
|
||||||
if ((mystreamer->base.bbs_buffer.maxlen - mystreamer->bytes_written) <
|
if ((mystreamer->base.bbs_buffer.maxlen - mystreamer->bytes_written) <
|
||||||
footer_bound)
|
footer_bound)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->bytes_written,
|
mystreamer->bytes_written,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
/* Enlarge buffer if it falls short of footer bound. */
|
/* Enlarge buffer if it falls short of footer bound. */
|
||||||
if (mystreamer->base.bbs_buffer.maxlen < footer_bound)
|
if (mystreamer->base.bbs_buffer.maxlen < footer_bound)
|
||||||
@ -243,24 +243,24 @@ bbstreamer_lz4_compressor_finalize(bbstreamer *streamer)
|
|||||||
|
|
||||||
mystreamer->bytes_written += compressed_size;
|
mystreamer->bytes_written += compressed_size;
|
||||||
|
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->bytes_written,
|
mystreamer->bytes_written,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
bbstreamer_finalize(mystreamer->base.bbs_next);
|
astreamer_finalize(mystreamer->base.bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory.
|
* Free memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_lz4_compressor_free(bbstreamer *streamer)
|
astreamer_lz4_compressor_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_lz4_frame *mystreamer;
|
astreamer_lz4_frame *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_lz4_frame *) streamer;
|
mystreamer = (astreamer_lz4_frame *) streamer;
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
LZ4F_freeCompressionContext(mystreamer->cctx);
|
LZ4F_freeCompressionContext(mystreamer->cctx);
|
||||||
pfree(streamer->bbs_buffer.data);
|
pfree(streamer->bbs_buffer.data);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
||||||
@ -271,18 +271,18 @@ bbstreamer_lz4_compressor_free(bbstreamer *streamer)
|
|||||||
* Create a new base backup streamer that performs decompression of lz4
|
* Create a new base backup streamer that performs decompression of lz4
|
||||||
* compressed blocks.
|
* compressed blocks.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_lz4_decompressor_new(bbstreamer *next)
|
astreamer_lz4_decompressor_new(astreamer *next)
|
||||||
{
|
{
|
||||||
#ifdef USE_LZ4
|
#ifdef USE_LZ4
|
||||||
bbstreamer_lz4_frame *streamer;
|
astreamer_lz4_frame *streamer;
|
||||||
LZ4F_errorCode_t ctxError;
|
LZ4F_errorCode_t ctxError;
|
||||||
|
|
||||||
Assert(next != NULL);
|
Assert(next != NULL);
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_lz4_frame));
|
streamer = palloc0(sizeof(astreamer_lz4_frame));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_lz4_decompressor_ops;
|
&astreamer_lz4_decompressor_ops;
|
||||||
|
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
initStringInfo(&streamer->base.bbs_buffer);
|
initStringInfo(&streamer->base.bbs_buffer);
|
||||||
@ -307,18 +307,18 @@ bbstreamer_lz4_decompressor_new(bbstreamer *next)
|
|||||||
* to the next streamer.
|
* to the next streamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_lz4_decompressor_content(bbstreamer *streamer,
|
astreamer_lz4_decompressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_lz4_frame *mystreamer;
|
astreamer_lz4_frame *mystreamer;
|
||||||
uint8 *next_in,
|
uint8 *next_in,
|
||||||
*next_out;
|
*next_out;
|
||||||
size_t avail_in,
|
size_t avail_in,
|
||||||
avail_out;
|
avail_out;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_lz4_frame *) streamer;
|
mystreamer = (astreamer_lz4_frame *) streamer;
|
||||||
next_in = (uint8 *) data;
|
next_in = (uint8 *) data;
|
||||||
next_out = (uint8 *) mystreamer->base.bbs_buffer.data;
|
next_out = (uint8 *) mystreamer->base.bbs_buffer.data;
|
||||||
avail_in = len;
|
avail_in = len;
|
||||||
@ -366,7 +366,7 @@ bbstreamer_lz4_decompressor_content(bbstreamer *streamer,
|
|||||||
*/
|
*/
|
||||||
if (mystreamer->bytes_written >= mystreamer->base.bbs_buffer.maxlen)
|
if (mystreamer->bytes_written >= mystreamer->base.bbs_buffer.maxlen)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->base.bbs_buffer.maxlen,
|
mystreamer->base.bbs_buffer.maxlen,
|
||||||
context);
|
context);
|
||||||
@ -387,34 +387,34 @@ bbstreamer_lz4_decompressor_content(bbstreamer *streamer,
|
|||||||
* End-of-stream processing.
|
* End-of-stream processing.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_lz4_decompressor_finalize(bbstreamer *streamer)
|
astreamer_lz4_decompressor_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_lz4_frame *mystreamer;
|
astreamer_lz4_frame *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_lz4_frame *) streamer;
|
mystreamer = (astreamer_lz4_frame *) streamer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of the stream, if there is some pending data in output buffers then
|
* End of the stream, if there is some pending data in output buffers then
|
||||||
* we must forward it to next streamer.
|
* we must forward it to next streamer.
|
||||||
*/
|
*/
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->base.bbs_buffer.maxlen,
|
mystreamer->base.bbs_buffer.maxlen,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
bbstreamer_finalize(mystreamer->base.bbs_next);
|
astreamer_finalize(mystreamer->base.bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory.
|
* Free memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_lz4_decompressor_free(bbstreamer *streamer)
|
astreamer_lz4_decompressor_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_lz4_frame *mystreamer;
|
astreamer_lz4_frame *mystreamer;
|
||||||
|
|
||||||
mystreamer = (bbstreamer_lz4_frame *) streamer;
|
mystreamer = (astreamer_lz4_frame *) streamer;
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
LZ4F_freeDecompressionContext(mystreamer->dctx);
|
LZ4F_freeDecompressionContext(mystreamer->dctx);
|
||||||
pfree(streamer->bbs_buffer.data);
|
pfree(streamer->bbs_buffer.data);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
@ -1,13 +1,13 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* bbstreamer_tar.c
|
* astreamer_tar.c
|
||||||
*
|
*
|
||||||
* This module implements three types of tar processing. A tar parser
|
* This module implements three types of tar processing. A tar parser
|
||||||
* expects unlabelled chunks of data (e.g. BBSTREAMER_UNKNOWN) and splits
|
* expects unlabelled chunks of data (e.g. ASTREAMER_UNKNOWN) and splits
|
||||||
* it into labelled chunks (any other value of bbstreamer_archive_context).
|
* it into labelled chunks (any other value of astreamer_archive_context).
|
||||||
* A tar archiver does the reverse: it takes a bunch of labelled chunks
|
* A tar archiver does the reverse: it takes a bunch of labelled chunks
|
||||||
* and produces a tarfile, optionally replacing member headers and trailers
|
* and produces a tarfile, optionally replacing member headers and trailers
|
||||||
* so that upstream bbstreamer objects can perform surgery on the tarfile
|
* so that upstream astreamer objects can perform surgery on the tarfile
|
||||||
* contents without knowing the details of the tar format. A tar terminator
|
* contents without knowing the details of the tar format. A tar terminator
|
||||||
* just adds two blocks of NUL bytes to the end of the file, since older
|
* just adds two blocks of NUL bytes to the end of the file, since older
|
||||||
* server versions produce files with this terminator omitted.
|
* server versions produce files with this terminator omitted.
|
||||||
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* src/bin/pg_basebackup/bbstreamer_tar.c
|
* src/bin/pg_basebackup/astreamer_tar.c
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -23,83 +23,83 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "bbstreamer.h"
|
#include "astreamer.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "pgtar.h"
|
#include "pgtar.h"
|
||||||
|
|
||||||
typedef struct bbstreamer_tar_parser
|
typedef struct astreamer_tar_parser
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
bbstreamer_archive_context next_context;
|
astreamer_archive_context next_context;
|
||||||
bbstreamer_member member;
|
astreamer_member member;
|
||||||
size_t file_bytes_sent;
|
size_t file_bytes_sent;
|
||||||
size_t pad_bytes_expected;
|
size_t pad_bytes_expected;
|
||||||
} bbstreamer_tar_parser;
|
} astreamer_tar_parser;
|
||||||
|
|
||||||
typedef struct bbstreamer_tar_archiver
|
typedef struct astreamer_tar_archiver
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
bool rearchive_member;
|
bool rearchive_member;
|
||||||
} bbstreamer_tar_archiver;
|
} astreamer_tar_archiver;
|
||||||
|
|
||||||
static void bbstreamer_tar_parser_content(bbstreamer *streamer,
|
static void astreamer_tar_parser_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_tar_parser_finalize(bbstreamer *streamer);
|
static void astreamer_tar_parser_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_tar_parser_free(bbstreamer *streamer);
|
static void astreamer_tar_parser_free(astreamer *streamer);
|
||||||
static bool bbstreamer_tar_header(bbstreamer_tar_parser *mystreamer);
|
static bool astreamer_tar_header(astreamer_tar_parser *mystreamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_tar_parser_ops = {
|
static const astreamer_ops astreamer_tar_parser_ops = {
|
||||||
.content = bbstreamer_tar_parser_content,
|
.content = astreamer_tar_parser_content,
|
||||||
.finalize = bbstreamer_tar_parser_finalize,
|
.finalize = astreamer_tar_parser_finalize,
|
||||||
.free = bbstreamer_tar_parser_free
|
.free = astreamer_tar_parser_free
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bbstreamer_tar_archiver_content(bbstreamer *streamer,
|
static void astreamer_tar_archiver_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_tar_archiver_finalize(bbstreamer *streamer);
|
static void astreamer_tar_archiver_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_tar_archiver_free(bbstreamer *streamer);
|
static void astreamer_tar_archiver_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_tar_archiver_ops = {
|
static const astreamer_ops astreamer_tar_archiver_ops = {
|
||||||
.content = bbstreamer_tar_archiver_content,
|
.content = astreamer_tar_archiver_content,
|
||||||
.finalize = bbstreamer_tar_archiver_finalize,
|
.finalize = astreamer_tar_archiver_finalize,
|
||||||
.free = bbstreamer_tar_archiver_free
|
.free = astreamer_tar_archiver_free
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bbstreamer_tar_terminator_content(bbstreamer *streamer,
|
static void astreamer_tar_terminator_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_tar_terminator_finalize(bbstreamer *streamer);
|
static void astreamer_tar_terminator_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_tar_terminator_free(bbstreamer *streamer);
|
static void astreamer_tar_terminator_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_tar_terminator_ops = {
|
static const astreamer_ops astreamer_tar_terminator_ops = {
|
||||||
.content = bbstreamer_tar_terminator_content,
|
.content = astreamer_tar_terminator_content,
|
||||||
.finalize = bbstreamer_tar_terminator_finalize,
|
.finalize = astreamer_tar_terminator_finalize,
|
||||||
.free = bbstreamer_tar_terminator_free
|
.free = astreamer_tar_terminator_free
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that can parse a stream of content as tar data.
|
* Create a astreamer that can parse a stream of content as tar data.
|
||||||
*
|
*
|
||||||
* The input should be a series of BBSTREAMER_UNKNOWN chunks; the bbstreamer
|
* The input should be a series of ASTREAMER_UNKNOWN chunks; the astreamer
|
||||||
* specified by 'next' will receive a series of typed chunks, as per the
|
* specified by 'next' will receive a series of typed chunks, as per the
|
||||||
* conventions described in bbstreamer.h.
|
* conventions described in astreamer.h.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_tar_parser_new(bbstreamer *next)
|
astreamer_tar_parser_new(astreamer *next)
|
||||||
{
|
{
|
||||||
bbstreamer_tar_parser *streamer;
|
astreamer_tar_parser *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_tar_parser));
|
streamer = palloc0(sizeof(astreamer_tar_parser));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_tar_parser_ops;
|
&astreamer_tar_parser_ops;
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
initStringInfo(&streamer->base.bbs_buffer);
|
initStringInfo(&streamer->base.bbs_buffer);
|
||||||
streamer->next_context = BBSTREAMER_MEMBER_HEADER;
|
streamer->next_context = ASTREAMER_MEMBER_HEADER;
|
||||||
|
|
||||||
return &streamer->base;
|
return &streamer->base;
|
||||||
}
|
}
|
||||||
@ -108,28 +108,28 @@ bbstreamer_tar_parser_new(bbstreamer *next)
|
|||||||
* Parse unknown content as tar data.
|
* Parse unknown content as tar data.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member,
|
astreamer_tar_parser_content(astreamer *streamer, astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_tar_parser *mystreamer = (bbstreamer_tar_parser *) streamer;
|
astreamer_tar_parser *mystreamer = (astreamer_tar_parser *) streamer;
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
|
||||||
/* Expect unparsed input. */
|
/* Expect unparsed input. */
|
||||||
Assert(member == NULL);
|
Assert(member == NULL);
|
||||||
Assert(context == BBSTREAMER_UNKNOWN);
|
Assert(context == ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
switch (mystreamer->next_context)
|
switch (mystreamer->next_context)
|
||||||
{
|
{
|
||||||
case BBSTREAMER_MEMBER_HEADER:
|
case ASTREAMER_MEMBER_HEADER:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're expecting an archive member header, accumulate a
|
* If we're expecting an archive member header, accumulate a
|
||||||
* full block of data before doing anything further.
|
* full block of data before doing anything further.
|
||||||
*/
|
*/
|
||||||
if (!bbstreamer_buffer_until(streamer, &data, &len,
|
if (!astreamer_buffer_until(streamer, &data, &len,
|
||||||
TAR_BLOCK_SIZE))
|
TAR_BLOCK_SIZE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -139,32 +139,32 @@ bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member,
|
|||||||
* thought was the next file header is actually the start of
|
* thought was the next file header is actually the start of
|
||||||
* the archive trailer. Switch modes accordingly.
|
* the archive trailer. Switch modes accordingly.
|
||||||
*/
|
*/
|
||||||
if (bbstreamer_tar_header(mystreamer))
|
if (astreamer_tar_header(mystreamer))
|
||||||
{
|
{
|
||||||
if (mystreamer->member.size == 0)
|
if (mystreamer->member.size == 0)
|
||||||
{
|
{
|
||||||
/* No content; trailer is zero-length. */
|
/* No content; trailer is zero-length. */
|
||||||
bbstreamer_content(mystreamer->base.bbs_next,
|
astreamer_content(mystreamer->base.bbs_next,
|
||||||
&mystreamer->member,
|
&mystreamer->member,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
BBSTREAMER_MEMBER_TRAILER);
|
ASTREAMER_MEMBER_TRAILER);
|
||||||
|
|
||||||
/* Expect next header. */
|
/* Expect next header. */
|
||||||
mystreamer->next_context = BBSTREAMER_MEMBER_HEADER;
|
mystreamer->next_context = ASTREAMER_MEMBER_HEADER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Expect contents. */
|
/* Expect contents. */
|
||||||
mystreamer->next_context = BBSTREAMER_MEMBER_CONTENTS;
|
mystreamer->next_context = ASTREAMER_MEMBER_CONTENTS;
|
||||||
}
|
}
|
||||||
mystreamer->base.bbs_buffer.len = 0;
|
mystreamer->base.bbs_buffer.len = 0;
|
||||||
mystreamer->file_bytes_sent = 0;
|
mystreamer->file_bytes_sent = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mystreamer->next_context = BBSTREAMER_ARCHIVE_TRAILER;
|
mystreamer->next_context = ASTREAMER_ARCHIVE_TRAILER;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_MEMBER_CONTENTS:
|
case ASTREAMER_MEMBER_CONTENTS:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send as much content as we have, but not more than the
|
* Send as much content as we have, but not more than the
|
||||||
@ -174,10 +174,10 @@ bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member,
|
|||||||
nbytes = mystreamer->member.size - mystreamer->file_bytes_sent;
|
nbytes = mystreamer->member.size - mystreamer->file_bytes_sent;
|
||||||
nbytes = Min(nbytes, len);
|
nbytes = Min(nbytes, len);
|
||||||
Assert(nbytes > 0);
|
Assert(nbytes > 0);
|
||||||
bbstreamer_content(mystreamer->base.bbs_next,
|
astreamer_content(mystreamer->base.bbs_next,
|
||||||
&mystreamer->member,
|
&mystreamer->member,
|
||||||
data, nbytes,
|
data, nbytes,
|
||||||
BBSTREAMER_MEMBER_CONTENTS);
|
ASTREAMER_MEMBER_CONTENTS);
|
||||||
mystreamer->file_bytes_sent += nbytes;
|
mystreamer->file_bytes_sent += nbytes;
|
||||||
data += nbytes;
|
data += nbytes;
|
||||||
len -= nbytes;
|
len -= nbytes;
|
||||||
@ -193,53 +193,53 @@ bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member,
|
|||||||
if (mystreamer->pad_bytes_expected == 0)
|
if (mystreamer->pad_bytes_expected == 0)
|
||||||
{
|
{
|
||||||
/* Trailer is zero-length. */
|
/* Trailer is zero-length. */
|
||||||
bbstreamer_content(mystreamer->base.bbs_next,
|
astreamer_content(mystreamer->base.bbs_next,
|
||||||
&mystreamer->member,
|
&mystreamer->member,
|
||||||
NULL, 0,
|
NULL, 0,
|
||||||
BBSTREAMER_MEMBER_TRAILER);
|
ASTREAMER_MEMBER_TRAILER);
|
||||||
|
|
||||||
/* Expect next header. */
|
/* Expect next header. */
|
||||||
mystreamer->next_context = BBSTREAMER_MEMBER_HEADER;
|
mystreamer->next_context = ASTREAMER_MEMBER_HEADER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Trailer is not zero-length. */
|
/* Trailer is not zero-length. */
|
||||||
mystreamer->next_context = BBSTREAMER_MEMBER_TRAILER;
|
mystreamer->next_context = ASTREAMER_MEMBER_TRAILER;
|
||||||
}
|
}
|
||||||
mystreamer->base.bbs_buffer.len = 0;
|
mystreamer->base.bbs_buffer.len = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_MEMBER_TRAILER:
|
case ASTREAMER_MEMBER_TRAILER:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're expecting an archive member trailer, accumulate
|
* If we're expecting an archive member trailer, accumulate
|
||||||
* the expected number of padding bytes before sending
|
* the expected number of padding bytes before sending
|
||||||
* anything onward.
|
* anything onward.
|
||||||
*/
|
*/
|
||||||
if (!bbstreamer_buffer_until(streamer, &data, &len,
|
if (!astreamer_buffer_until(streamer, &data, &len,
|
||||||
mystreamer->pad_bytes_expected))
|
mystreamer->pad_bytes_expected))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* OK, now we can send it. */
|
/* OK, now we can send it. */
|
||||||
bbstreamer_content(mystreamer->base.bbs_next,
|
astreamer_content(mystreamer->base.bbs_next,
|
||||||
&mystreamer->member,
|
&mystreamer->member,
|
||||||
data, mystreamer->pad_bytes_expected,
|
data, mystreamer->pad_bytes_expected,
|
||||||
BBSTREAMER_MEMBER_TRAILER);
|
ASTREAMER_MEMBER_TRAILER);
|
||||||
|
|
||||||
/* Expect next file header. */
|
/* Expect next file header. */
|
||||||
mystreamer->next_context = BBSTREAMER_MEMBER_HEADER;
|
mystreamer->next_context = ASTREAMER_MEMBER_HEADER;
|
||||||
mystreamer->base.bbs_buffer.len = 0;
|
mystreamer->base.bbs_buffer.len = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BBSTREAMER_ARCHIVE_TRAILER:
|
case ASTREAMER_ARCHIVE_TRAILER:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We've seen an end-of-archive indicator, so anything more is
|
* We've seen an end-of-archive indicator, so anything more is
|
||||||
* buffered and sent as part of the archive trailer. But we
|
* buffered and sent as part of the archive trailer. But we
|
||||||
* don't expect more than 2 blocks.
|
* don't expect more than 2 blocks.
|
||||||
*/
|
*/
|
||||||
bbstreamer_buffer_bytes(streamer, &data, &len, len);
|
astreamer_buffer_bytes(streamer, &data, &len, len);
|
||||||
if (len > 2 * TAR_BLOCK_SIZE)
|
if (len > 2 * TAR_BLOCK_SIZE)
|
||||||
pg_fatal("tar file trailer exceeds 2 blocks");
|
pg_fatal("tar file trailer exceeds 2 blocks");
|
||||||
return;
|
return;
|
||||||
@ -255,14 +255,14 @@ bbstreamer_tar_parser_content(bbstreamer *streamer, bbstreamer_member *member,
|
|||||||
* Parse a file header within a tar stream.
|
* Parse a file header within a tar stream.
|
||||||
*
|
*
|
||||||
* The return value is true if we found a file header and passed it on to the
|
* The return value is true if we found a file header and passed it on to the
|
||||||
* next bbstreamer; it is false if we have reached the archive trailer.
|
* next astreamer; it is false if we have reached the archive trailer.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
bbstreamer_tar_header(bbstreamer_tar_parser *mystreamer)
|
astreamer_tar_header(astreamer_tar_parser *mystreamer)
|
||||||
{
|
{
|
||||||
bool has_nonzero_byte = false;
|
bool has_nonzero_byte = false;
|
||||||
int i;
|
int i;
|
||||||
bbstreamer_member *member = &mystreamer->member;
|
astreamer_member *member = &mystreamer->member;
|
||||||
char *buffer = mystreamer->base.bbs_buffer.data;
|
char *buffer = mystreamer->base.bbs_buffer.data;
|
||||||
|
|
||||||
Assert(mystreamer->base.bbs_buffer.len == TAR_BLOCK_SIZE);
|
Assert(mystreamer->base.bbs_buffer.len == TAR_BLOCK_SIZE);
|
||||||
@ -304,10 +304,10 @@ bbstreamer_tar_header(bbstreamer_tar_parser *mystreamer)
|
|||||||
/* Compute number of padding bytes. */
|
/* Compute number of padding bytes. */
|
||||||
mystreamer->pad_bytes_expected = tarPaddingBytesRequired(member->size);
|
mystreamer->pad_bytes_expected = tarPaddingBytesRequired(member->size);
|
||||||
|
|
||||||
/* Forward the entire header to the next bbstreamer. */
|
/* Forward the entire header to the next astreamer. */
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
buffer, TAR_BLOCK_SIZE,
|
buffer, TAR_BLOCK_SIZE,
|
||||||
BBSTREAMER_MEMBER_HEADER);
|
ASTREAMER_MEMBER_HEADER);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -316,50 +316,50 @@ bbstreamer_tar_header(bbstreamer_tar_parser *mystreamer)
|
|||||||
* End-of-stream processing for a tar parser.
|
* End-of-stream processing for a tar parser.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_parser_finalize(bbstreamer *streamer)
|
astreamer_tar_parser_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_tar_parser *mystreamer = (bbstreamer_tar_parser *) streamer;
|
astreamer_tar_parser *mystreamer = (astreamer_tar_parser *) streamer;
|
||||||
|
|
||||||
if (mystreamer->next_context != BBSTREAMER_ARCHIVE_TRAILER &&
|
if (mystreamer->next_context != ASTREAMER_ARCHIVE_TRAILER &&
|
||||||
(mystreamer->next_context != BBSTREAMER_MEMBER_HEADER ||
|
(mystreamer->next_context != ASTREAMER_MEMBER_HEADER ||
|
||||||
mystreamer->base.bbs_buffer.len > 0))
|
mystreamer->base.bbs_buffer.len > 0))
|
||||||
pg_fatal("COPY stream ended before last file was finished");
|
pg_fatal("COPY stream ended before last file was finished");
|
||||||
|
|
||||||
/* Send the archive trailer, even if empty. */
|
/* Send the archive trailer, even if empty. */
|
||||||
bbstreamer_content(streamer->bbs_next, NULL,
|
astreamer_content(streamer->bbs_next, NULL,
|
||||||
streamer->bbs_buffer.data, streamer->bbs_buffer.len,
|
streamer->bbs_buffer.data, streamer->bbs_buffer.len,
|
||||||
BBSTREAMER_ARCHIVE_TRAILER);
|
ASTREAMER_ARCHIVE_TRAILER);
|
||||||
|
|
||||||
/* Now finalize successor. */
|
/* Now finalize successor. */
|
||||||
bbstreamer_finalize(streamer->bbs_next);
|
astreamer_finalize(streamer->bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory associated with a tar parser.
|
* Free memory associated with a tar parser.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_parser_free(bbstreamer *streamer)
|
astreamer_tar_parser_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
pfree(streamer->bbs_buffer.data);
|
pfree(streamer->bbs_buffer.data);
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that can generate a tar archive.
|
* Create a astreamer that can generate a tar archive.
|
||||||
*
|
*
|
||||||
* This is intended to be usable either for generating a brand-new tar archive
|
* This is intended to be usable either for generating a brand-new tar archive
|
||||||
* or for modifying one on the fly. The input should be a series of typed
|
* or for modifying one on the fly. The input should be a series of typed
|
||||||
* chunks (i.e. not BBSTREAMER_UNKNOWN). See also the comments for
|
* chunks (i.e. not ASTREAMER_UNKNOWN). See also the comments for
|
||||||
* bbstreamer_tar_parser_content.
|
* astreamer_tar_parser_content.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_tar_archiver_new(bbstreamer *next)
|
astreamer_tar_archiver_new(astreamer *next)
|
||||||
{
|
{
|
||||||
bbstreamer_tar_archiver *streamer;
|
astreamer_tar_archiver *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_tar_archiver));
|
streamer = palloc0(sizeof(astreamer_tar_archiver));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_tar_archiver_ops;
|
&astreamer_tar_archiver_ops;
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
|
|
||||||
return &streamer->base;
|
return &streamer->base;
|
||||||
@ -368,36 +368,36 @@ bbstreamer_tar_archiver_new(bbstreamer *next)
|
|||||||
/*
|
/*
|
||||||
* Fix up the stream of input chunks to create a valid tar file.
|
* Fix up the stream of input chunks to create a valid tar file.
|
||||||
*
|
*
|
||||||
* If a BBSTREAMER_MEMBER_HEADER chunk is of size 0, it is replaced with a
|
* If a ASTREAMER_MEMBER_HEADER chunk is of size 0, it is replaced with a
|
||||||
* newly-constructed tar header. If it is of size TAR_BLOCK_SIZE, it is
|
* newly-constructed tar header. If it is of size TAR_BLOCK_SIZE, it is
|
||||||
* passed through without change. Any other size is a fatal error (and
|
* passed through without change. Any other size is a fatal error (and
|
||||||
* indicates a bug).
|
* indicates a bug).
|
||||||
*
|
*
|
||||||
* Whenever a new BBSTREAMER_MEMBER_HEADER chunk is constructed, the
|
* Whenever a new ASTREAMER_MEMBER_HEADER chunk is constructed, the
|
||||||
* corresponding BBSTREAMER_MEMBER_TRAILER chunk is also constructed from
|
* corresponding ASTREAMER_MEMBER_TRAILER chunk is also constructed from
|
||||||
* scratch. Specifically, we construct a block of zero bytes sufficient to
|
* scratch. Specifically, we construct a block of zero bytes sufficient to
|
||||||
* pad out to a block boundary, as required by the tar format. Other
|
* pad out to a block boundary, as required by the tar format. Other
|
||||||
* BBSTREAMER_MEMBER_TRAILER chunks are passed through without change.
|
* ASTREAMER_MEMBER_TRAILER chunks are passed through without change.
|
||||||
*
|
*
|
||||||
* Any BBSTREAMER_MEMBER_CONTENTS chunks are passed through without change.
|
* Any ASTREAMER_MEMBER_CONTENTS chunks are passed through without change.
|
||||||
*
|
*
|
||||||
* The BBSTREAMER_ARCHIVE_TRAILER chunk is replaced with two
|
* The ASTREAMER_ARCHIVE_TRAILER chunk is replaced with two
|
||||||
* blocks of zero bytes. Not all tar programs require this, but apparently
|
* blocks of zero bytes. Not all tar programs require this, but apparently
|
||||||
* some do. The server does not supply this trailer. If no archive trailer is
|
* some do. The server does not supply this trailer. If no archive trailer is
|
||||||
* present, one will be added by bbstreamer_tar_parser_finalize.
|
* present, one will be added by astreamer_tar_parser_finalize.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_archiver_content(bbstreamer *streamer,
|
astreamer_tar_archiver_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_tar_archiver *mystreamer = (bbstreamer_tar_archiver *) streamer;
|
astreamer_tar_archiver *mystreamer = (astreamer_tar_archiver *) streamer;
|
||||||
char buffer[2 * TAR_BLOCK_SIZE];
|
char buffer[2 * TAR_BLOCK_SIZE];
|
||||||
|
|
||||||
Assert(context != BBSTREAMER_UNKNOWN);
|
Assert(context != ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
if (context == BBSTREAMER_MEMBER_HEADER && len != TAR_BLOCK_SIZE)
|
if (context == ASTREAMER_MEMBER_HEADER && len != TAR_BLOCK_SIZE)
|
||||||
{
|
{
|
||||||
Assert(len == 0);
|
Assert(len == 0);
|
||||||
|
|
||||||
@ -411,7 +411,7 @@ bbstreamer_tar_archiver_content(bbstreamer *streamer,
|
|||||||
/* Also make a note to replace padding, in case size changed. */
|
/* Also make a note to replace padding, in case size changed. */
|
||||||
mystreamer->rearchive_member = true;
|
mystreamer->rearchive_member = true;
|
||||||
}
|
}
|
||||||
else if (context == BBSTREAMER_MEMBER_TRAILER &&
|
else if (context == ASTREAMER_MEMBER_TRAILER &&
|
||||||
mystreamer->rearchive_member)
|
mystreamer->rearchive_member)
|
||||||
{
|
{
|
||||||
int pad_bytes = tarPaddingBytesRequired(member->size);
|
int pad_bytes = tarPaddingBytesRequired(member->size);
|
||||||
@ -424,7 +424,7 @@ bbstreamer_tar_archiver_content(bbstreamer *streamer,
|
|||||||
/* Don't do this again unless we replace another header. */
|
/* Don't do this again unless we replace another header. */
|
||||||
mystreamer->rearchive_member = false;
|
mystreamer->rearchive_member = false;
|
||||||
}
|
}
|
||||||
else if (context == BBSTREAMER_ARCHIVE_TRAILER)
|
else if (context == ASTREAMER_ARCHIVE_TRAILER)
|
||||||
{
|
{
|
||||||
/* Trailer should always be two blocks of zero bytes. */
|
/* Trailer should always be two blocks of zero bytes. */
|
||||||
memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
|
memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
|
||||||
@ -432,40 +432,40 @@ bbstreamer_tar_archiver_content(bbstreamer *streamer,
|
|||||||
len = 2 * TAR_BLOCK_SIZE;
|
len = 2 * TAR_BLOCK_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bbstreamer_content(streamer->bbs_next, member, data, len, context);
|
astreamer_content(streamer->bbs_next, member, data, len, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End-of-stream processing for a tar archiver.
|
* End-of-stream processing for a tar archiver.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_archiver_finalize(bbstreamer *streamer)
|
astreamer_tar_archiver_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_finalize(streamer->bbs_next);
|
astreamer_finalize(streamer->bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory associated with a tar archiver.
|
* Free memory associated with a tar archiver.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_archiver_free(bbstreamer *streamer)
|
astreamer_tar_archiver_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a bbstreamer that blindly adds two blocks of NUL bytes to the
|
* Create a astreamer that blindly adds two blocks of NUL bytes to the
|
||||||
* end of an incomplete tarfile that the server might send us.
|
* end of an incomplete tarfile that the server might send us.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_tar_terminator_new(bbstreamer *next)
|
astreamer_tar_terminator_new(astreamer *next)
|
||||||
{
|
{
|
||||||
bbstreamer *streamer;
|
astreamer *streamer;
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer));
|
streamer = palloc0(sizeof(astreamer));
|
||||||
*((const bbstreamer_ops **) &streamer->bbs_ops) =
|
*((const astreamer_ops **) &streamer->bbs_ops) =
|
||||||
&bbstreamer_tar_terminator_ops;
|
&astreamer_tar_terminator_ops;
|
||||||
streamer->bbs_next = next;
|
streamer->bbs_next = next;
|
||||||
|
|
||||||
return streamer;
|
return streamer;
|
||||||
@ -475,17 +475,17 @@ bbstreamer_tar_terminator_new(bbstreamer *next)
|
|||||||
* Pass all the content through without change.
|
* Pass all the content through without change.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_terminator_content(bbstreamer *streamer,
|
astreamer_tar_terminator_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
/* Expect unparsed input. */
|
/* Expect unparsed input. */
|
||||||
Assert(member == NULL);
|
Assert(member == NULL);
|
||||||
Assert(context == BBSTREAMER_UNKNOWN);
|
Assert(context == ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
/* Just forward it. */
|
/* Just forward it. */
|
||||||
bbstreamer_content(streamer->bbs_next, member, data, len, context);
|
astreamer_content(streamer->bbs_next, member, data, len, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -493,22 +493,22 @@ bbstreamer_tar_terminator_content(bbstreamer *streamer,
|
|||||||
* to supply.
|
* to supply.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_terminator_finalize(bbstreamer *streamer)
|
astreamer_tar_terminator_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
char buffer[2 * TAR_BLOCK_SIZE];
|
char buffer[2 * TAR_BLOCK_SIZE];
|
||||||
|
|
||||||
memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
|
memset(buffer, 0, 2 * TAR_BLOCK_SIZE);
|
||||||
bbstreamer_content(streamer->bbs_next, NULL, buffer,
|
astreamer_content(streamer->bbs_next, NULL, buffer,
|
||||||
2 * TAR_BLOCK_SIZE, BBSTREAMER_UNKNOWN);
|
2 * TAR_BLOCK_SIZE, ASTREAMER_UNKNOWN);
|
||||||
bbstreamer_finalize(streamer->bbs_next);
|
astreamer_finalize(streamer->bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory associated with a tar terminator.
|
* Free memory associated with a tar terminator.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_tar_terminator_free(bbstreamer *streamer)
|
astreamer_tar_terminator_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* bbstreamer_zstd.c
|
* astreamer_zstd.c
|
||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* src/bin/pg_basebackup/bbstreamer_zstd.c
|
* src/bin/pg_basebackup/astreamer_zstd.c
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -17,44 +17,44 @@
|
|||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "bbstreamer.h"
|
#include "astreamer.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
|
|
||||||
#ifdef USE_ZSTD
|
#ifdef USE_ZSTD
|
||||||
|
|
||||||
typedef struct bbstreamer_zstd_frame
|
typedef struct astreamer_zstd_frame
|
||||||
{
|
{
|
||||||
bbstreamer base;
|
astreamer base;
|
||||||
|
|
||||||
ZSTD_CCtx *cctx;
|
ZSTD_CCtx *cctx;
|
||||||
ZSTD_DCtx *dctx;
|
ZSTD_DCtx *dctx;
|
||||||
ZSTD_outBuffer zstd_outBuf;
|
ZSTD_outBuffer zstd_outBuf;
|
||||||
} bbstreamer_zstd_frame;
|
} astreamer_zstd_frame;
|
||||||
|
|
||||||
static void bbstreamer_zstd_compressor_content(bbstreamer *streamer,
|
static void astreamer_zstd_compressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_zstd_compressor_finalize(bbstreamer *streamer);
|
static void astreamer_zstd_compressor_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_zstd_compressor_free(bbstreamer *streamer);
|
static void astreamer_zstd_compressor_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_zstd_compressor_ops = {
|
static const astreamer_ops astreamer_zstd_compressor_ops = {
|
||||||
.content = bbstreamer_zstd_compressor_content,
|
.content = astreamer_zstd_compressor_content,
|
||||||
.finalize = bbstreamer_zstd_compressor_finalize,
|
.finalize = astreamer_zstd_compressor_finalize,
|
||||||
.free = bbstreamer_zstd_compressor_free
|
.free = astreamer_zstd_compressor_free
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bbstreamer_zstd_decompressor_content(bbstreamer *streamer,
|
static void astreamer_zstd_decompressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context);
|
astreamer_archive_context context);
|
||||||
static void bbstreamer_zstd_decompressor_finalize(bbstreamer *streamer);
|
static void astreamer_zstd_decompressor_finalize(astreamer *streamer);
|
||||||
static void bbstreamer_zstd_decompressor_free(bbstreamer *streamer);
|
static void astreamer_zstd_decompressor_free(astreamer *streamer);
|
||||||
|
|
||||||
static const bbstreamer_ops bbstreamer_zstd_decompressor_ops = {
|
static const astreamer_ops astreamer_zstd_decompressor_ops = {
|
||||||
.content = bbstreamer_zstd_decompressor_content,
|
.content = astreamer_zstd_decompressor_content,
|
||||||
.finalize = bbstreamer_zstd_decompressor_finalize,
|
.finalize = astreamer_zstd_decompressor_finalize,
|
||||||
.free = bbstreamer_zstd_decompressor_free
|
.free = astreamer_zstd_decompressor_free
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -62,19 +62,19 @@ static const bbstreamer_ops bbstreamer_zstd_decompressor_ops = {
|
|||||||
* Create a new base backup streamer that performs zstd compression of tar
|
* Create a new base backup streamer that performs zstd compression of tar
|
||||||
* blocks.
|
* blocks.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_zstd_compressor_new(bbstreamer *next, pg_compress_specification *compress)
|
astreamer_zstd_compressor_new(astreamer *next, pg_compress_specification *compress)
|
||||||
{
|
{
|
||||||
#ifdef USE_ZSTD
|
#ifdef USE_ZSTD
|
||||||
bbstreamer_zstd_frame *streamer;
|
astreamer_zstd_frame *streamer;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
|
|
||||||
Assert(next != NULL);
|
Assert(next != NULL);
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_zstd_frame));
|
streamer = palloc0(sizeof(astreamer_zstd_frame));
|
||||||
|
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_zstd_compressor_ops;
|
&astreamer_zstd_compressor_ops;
|
||||||
|
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
initStringInfo(&streamer->base.bbs_buffer);
|
initStringInfo(&streamer->base.bbs_buffer);
|
||||||
@ -142,12 +142,12 @@ bbstreamer_zstd_compressor_new(bbstreamer *next, pg_compress_specification *comp
|
|||||||
* of output buffer to next streamer and empty the buffer.
|
* of output buffer to next streamer and empty the buffer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_zstd_compressor_content(bbstreamer *streamer,
|
astreamer_zstd_compressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_zstd_frame *mystreamer = (bbstreamer_zstd_frame *) streamer;
|
astreamer_zstd_frame *mystreamer = (astreamer_zstd_frame *) streamer;
|
||||||
ZSTD_inBuffer inBuf = {data, len, 0};
|
ZSTD_inBuffer inBuf = {data, len, 0};
|
||||||
|
|
||||||
while (inBuf.pos < inBuf.size)
|
while (inBuf.pos < inBuf.size)
|
||||||
@ -162,7 +162,7 @@ bbstreamer_zstd_compressor_content(bbstreamer *streamer,
|
|||||||
if (mystreamer->zstd_outBuf.size - mystreamer->zstd_outBuf.pos <
|
if (mystreamer->zstd_outBuf.size - mystreamer->zstd_outBuf.pos <
|
||||||
max_needed)
|
max_needed)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
mystreamer->zstd_outBuf.dst,
|
mystreamer->zstd_outBuf.dst,
|
||||||
mystreamer->zstd_outBuf.pos,
|
mystreamer->zstd_outBuf.pos,
|
||||||
context);
|
context);
|
||||||
@ -187,9 +187,9 @@ bbstreamer_zstd_compressor_content(bbstreamer *streamer,
|
|||||||
* End-of-stream processing.
|
* End-of-stream processing.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_zstd_compressor_finalize(bbstreamer *streamer)
|
astreamer_zstd_compressor_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_zstd_frame *mystreamer = (bbstreamer_zstd_frame *) streamer;
|
astreamer_zstd_frame *mystreamer = (astreamer_zstd_frame *) streamer;
|
||||||
size_t yet_to_flush;
|
size_t yet_to_flush;
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -204,10 +204,10 @@ bbstreamer_zstd_compressor_finalize(bbstreamer *streamer)
|
|||||||
if (mystreamer->zstd_outBuf.size - mystreamer->zstd_outBuf.pos <
|
if (mystreamer->zstd_outBuf.size - mystreamer->zstd_outBuf.pos <
|
||||||
max_needed)
|
max_needed)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->zstd_outBuf.dst,
|
mystreamer->zstd_outBuf.dst,
|
||||||
mystreamer->zstd_outBuf.pos,
|
mystreamer->zstd_outBuf.pos,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
/* Reset the ZSTD output buffer. */
|
/* Reset the ZSTD output buffer. */
|
||||||
mystreamer->zstd_outBuf.dst = mystreamer->base.bbs_buffer.data;
|
mystreamer->zstd_outBuf.dst = mystreamer->base.bbs_buffer.data;
|
||||||
@ -227,23 +227,23 @@ bbstreamer_zstd_compressor_finalize(bbstreamer *streamer)
|
|||||||
|
|
||||||
/* Make sure to pass any remaining bytes to the next streamer. */
|
/* Make sure to pass any remaining bytes to the next streamer. */
|
||||||
if (mystreamer->zstd_outBuf.pos > 0)
|
if (mystreamer->zstd_outBuf.pos > 0)
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->zstd_outBuf.dst,
|
mystreamer->zstd_outBuf.dst,
|
||||||
mystreamer->zstd_outBuf.pos,
|
mystreamer->zstd_outBuf.pos,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
bbstreamer_finalize(mystreamer->base.bbs_next);
|
astreamer_finalize(mystreamer->base.bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory.
|
* Free memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_zstd_compressor_free(bbstreamer *streamer)
|
astreamer_zstd_compressor_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_zstd_frame *mystreamer = (bbstreamer_zstd_frame *) streamer;
|
astreamer_zstd_frame *mystreamer = (astreamer_zstd_frame *) streamer;
|
||||||
|
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
ZSTD_freeCCtx(mystreamer->cctx);
|
ZSTD_freeCCtx(mystreamer->cctx);
|
||||||
pfree(streamer->bbs_buffer.data);
|
pfree(streamer->bbs_buffer.data);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
||||||
@ -254,17 +254,17 @@ bbstreamer_zstd_compressor_free(bbstreamer *streamer)
|
|||||||
* Create a new base backup streamer that performs decompression of zstd
|
* Create a new base backup streamer that performs decompression of zstd
|
||||||
* compressed blocks.
|
* compressed blocks.
|
||||||
*/
|
*/
|
||||||
bbstreamer *
|
astreamer *
|
||||||
bbstreamer_zstd_decompressor_new(bbstreamer *next)
|
astreamer_zstd_decompressor_new(astreamer *next)
|
||||||
{
|
{
|
||||||
#ifdef USE_ZSTD
|
#ifdef USE_ZSTD
|
||||||
bbstreamer_zstd_frame *streamer;
|
astreamer_zstd_frame *streamer;
|
||||||
|
|
||||||
Assert(next != NULL);
|
Assert(next != NULL);
|
||||||
|
|
||||||
streamer = palloc0(sizeof(bbstreamer_zstd_frame));
|
streamer = palloc0(sizeof(astreamer_zstd_frame));
|
||||||
*((const bbstreamer_ops **) &streamer->base.bbs_ops) =
|
*((const astreamer_ops **) &streamer->base.bbs_ops) =
|
||||||
&bbstreamer_zstd_decompressor_ops;
|
&astreamer_zstd_decompressor_ops;
|
||||||
|
|
||||||
streamer->base.bbs_next = next;
|
streamer->base.bbs_next = next;
|
||||||
initStringInfo(&streamer->base.bbs_buffer);
|
initStringInfo(&streamer->base.bbs_buffer);
|
||||||
@ -293,12 +293,12 @@ bbstreamer_zstd_decompressor_new(bbstreamer *next)
|
|||||||
* to the next streamer.
|
* to the next streamer.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_zstd_decompressor_content(bbstreamer *streamer,
|
astreamer_zstd_decompressor_content(astreamer *streamer,
|
||||||
bbstreamer_member *member,
|
astreamer_member *member,
|
||||||
const char *data, int len,
|
const char *data, int len,
|
||||||
bbstreamer_archive_context context)
|
astreamer_archive_context context)
|
||||||
{
|
{
|
||||||
bbstreamer_zstd_frame *mystreamer = (bbstreamer_zstd_frame *) streamer;
|
astreamer_zstd_frame *mystreamer = (astreamer_zstd_frame *) streamer;
|
||||||
ZSTD_inBuffer inBuf = {data, len, 0};
|
ZSTD_inBuffer inBuf = {data, len, 0};
|
||||||
|
|
||||||
while (inBuf.pos < inBuf.size)
|
while (inBuf.pos < inBuf.size)
|
||||||
@ -311,7 +311,7 @@ bbstreamer_zstd_decompressor_content(bbstreamer *streamer,
|
|||||||
*/
|
*/
|
||||||
if (mystreamer->zstd_outBuf.pos >= mystreamer->zstd_outBuf.size)
|
if (mystreamer->zstd_outBuf.pos >= mystreamer->zstd_outBuf.size)
|
||||||
{
|
{
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, member,
|
astreamer_content(mystreamer->base.bbs_next, member,
|
||||||
mystreamer->zstd_outBuf.dst,
|
mystreamer->zstd_outBuf.dst,
|
||||||
mystreamer->zstd_outBuf.pos,
|
mystreamer->zstd_outBuf.pos,
|
||||||
context);
|
context);
|
||||||
@ -335,32 +335,32 @@ bbstreamer_zstd_decompressor_content(bbstreamer *streamer,
|
|||||||
* End-of-stream processing.
|
* End-of-stream processing.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_zstd_decompressor_finalize(bbstreamer *streamer)
|
astreamer_zstd_decompressor_finalize(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_zstd_frame *mystreamer = (bbstreamer_zstd_frame *) streamer;
|
astreamer_zstd_frame *mystreamer = (astreamer_zstd_frame *) streamer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of the stream, if there is some pending data in output buffers then
|
* End of the stream, if there is some pending data in output buffers then
|
||||||
* we must forward it to next streamer.
|
* we must forward it to next streamer.
|
||||||
*/
|
*/
|
||||||
if (mystreamer->zstd_outBuf.pos > 0)
|
if (mystreamer->zstd_outBuf.pos > 0)
|
||||||
bbstreamer_content(mystreamer->base.bbs_next, NULL,
|
astreamer_content(mystreamer->base.bbs_next, NULL,
|
||||||
mystreamer->base.bbs_buffer.data,
|
mystreamer->base.bbs_buffer.data,
|
||||||
mystreamer->base.bbs_buffer.maxlen,
|
mystreamer->base.bbs_buffer.maxlen,
|
||||||
BBSTREAMER_UNKNOWN);
|
ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
bbstreamer_finalize(mystreamer->base.bbs_next);
|
astreamer_finalize(mystreamer->base.bbs_next);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free memory.
|
* Free memory.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bbstreamer_zstd_decompressor_free(bbstreamer *streamer)
|
astreamer_zstd_decompressor_free(astreamer *streamer)
|
||||||
{
|
{
|
||||||
bbstreamer_zstd_frame *mystreamer = (bbstreamer_zstd_frame *) streamer;
|
astreamer_zstd_frame *mystreamer = (astreamer_zstd_frame *) streamer;
|
||||||
|
|
||||||
bbstreamer_free(streamer->bbs_next);
|
astreamer_free(streamer->bbs_next);
|
||||||
ZSTD_freeDCtx(mystreamer->dctx);
|
ZSTD_freeDCtx(mystreamer->dctx);
|
||||||
pfree(streamer->bbs_buffer.data);
|
pfree(streamer->bbs_buffer.data);
|
||||||
pfree(streamer);
|
pfree(streamer);
|
@ -1,226 +0,0 @@
|
|||||||
/*-------------------------------------------------------------------------
|
|
||||||
*
|
|
||||||
* bbstreamer.h
|
|
||||||
*
|
|
||||||
* Each tar archive returned by the server is passed to one or more
|
|
||||||
* bbstreamer objects for further processing. The bbstreamer may do
|
|
||||||
* something simple, like write the archive to a file, perhaps after
|
|
||||||
* compressing it, but it can also do more complicated things, like
|
|
||||||
* annotating the byte stream to indicate which parts of the data
|
|
||||||
* correspond to tar headers or trailing padding, vs. which parts are
|
|
||||||
* payload data. A subsequent bbstreamer may use this information to
|
|
||||||
* make further decisions about how to process the data; for example,
|
|
||||||
* it might choose to modify the archive contents.
|
|
||||||
*
|
|
||||||
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
|
||||||
*
|
|
||||||
* IDENTIFICATION
|
|
||||||
* src/bin/pg_basebackup/bbstreamer.h
|
|
||||||
*-------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef BBSTREAMER_H
|
|
||||||
#define BBSTREAMER_H
|
|
||||||
|
|
||||||
#include "common/compression.h"
|
|
||||||
#include "lib/stringinfo.h"
|
|
||||||
#include "pqexpbuffer.h"
|
|
||||||
|
|
||||||
struct bbstreamer;
|
|
||||||
struct bbstreamer_ops;
|
|
||||||
typedef struct bbstreamer bbstreamer;
|
|
||||||
typedef struct bbstreamer_ops bbstreamer_ops;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Each chunk of archive data passed to a bbstreamer is classified into one
|
|
||||||
* of these categories. When data is first received from the remote server,
|
|
||||||
* each chunk will be categorized as BBSTREAMER_UNKNOWN, and the chunks will
|
|
||||||
* be of whatever size the remote server chose to send.
|
|
||||||
*
|
|
||||||
* If the archive is parsed (e.g. see bbstreamer_tar_parser_new()), then all
|
|
||||||
* chunks should be labelled as one of the other types listed here. In
|
|
||||||
* addition, there should be exactly one BBSTREAMER_MEMBER_HEADER chunk and
|
|
||||||
* exactly one BBSTREAMER_MEMBER_TRAILER chunk per archive member, even if
|
|
||||||
* that means a zero-length call. There can be any number of
|
|
||||||
* BBSTREAMER_MEMBER_CONTENTS chunks in between those calls. There
|
|
||||||
* should exactly BBSTREAMER_ARCHIVE_TRAILER chunk, and it should follow the
|
|
||||||
* last BBSTREAMER_MEMBER_TRAILER chunk.
|
|
||||||
*
|
|
||||||
* In theory, we could need other classifications here, such as a way of
|
|
||||||
* indicating an archive header, but the "tar" format doesn't need anything
|
|
||||||
* else, so for the time being there's no point.
|
|
||||||
*/
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
BBSTREAMER_UNKNOWN,
|
|
||||||
BBSTREAMER_MEMBER_HEADER,
|
|
||||||
BBSTREAMER_MEMBER_CONTENTS,
|
|
||||||
BBSTREAMER_MEMBER_TRAILER,
|
|
||||||
BBSTREAMER_ARCHIVE_TRAILER,
|
|
||||||
} bbstreamer_archive_context;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Each chunk of data that is classified as BBSTREAMER_MEMBER_HEADER,
|
|
||||||
* BBSTREAMER_MEMBER_CONTENTS, or BBSTREAMER_MEMBER_TRAILER should also
|
|
||||||
* pass a pointer to an instance of this struct. The details are expected
|
|
||||||
* to be present in the archive header and used to fill the struct, after
|
|
||||||
* which all subsequent calls for the same archive member are expected to
|
|
||||||
* pass the same details.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char pathname[MAXPGPATH];
|
|
||||||
pgoff_t size;
|
|
||||||
mode_t mode;
|
|
||||||
uid_t uid;
|
|
||||||
gid_t gid;
|
|
||||||
bool is_directory;
|
|
||||||
bool is_link;
|
|
||||||
char linktarget[MAXPGPATH];
|
|
||||||
} bbstreamer_member;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generally, each type of bbstreamer will define its own struct, but the
|
|
||||||
* first element should be 'bbstreamer base'. A bbstreamer that does not
|
|
||||||
* require any additional private data could use this structure directly.
|
|
||||||
*
|
|
||||||
* bbs_ops is a pointer to the bbstreamer_ops object which contains the
|
|
||||||
* function pointers appropriate to this type of bbstreamer.
|
|
||||||
*
|
|
||||||
* bbs_next is a pointer to the successor bbstreamer, for those types of
|
|
||||||
* bbstreamer which forward data to a successor. It need not be used and
|
|
||||||
* should be set to NULL when not relevant.
|
|
||||||
*
|
|
||||||
* bbs_buffer is a buffer for accumulating data for temporary storage. Each
|
|
||||||
* type of bbstreamer makes its own decisions about whether and how to use
|
|
||||||
* this buffer.
|
|
||||||
*/
|
|
||||||
struct bbstreamer
|
|
||||||
{
|
|
||||||
const bbstreamer_ops *bbs_ops;
|
|
||||||
bbstreamer *bbs_next;
|
|
||||||
StringInfoData bbs_buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There are three callbacks for a bbstreamer. The 'content' callback is
|
|
||||||
* called repeatedly, as described in the bbstreamer_archive_context comments.
|
|
||||||
* Then, the 'finalize' callback is called once at the end, to give the
|
|
||||||
* bbstreamer a chance to perform cleanup such as closing files. Finally,
|
|
||||||
* because this code is running in a frontend environment where, as of this
|
|
||||||
* writing, there are no memory contexts, the 'free' callback is called to
|
|
||||||
* release memory. These callbacks should always be invoked using the static
|
|
||||||
* inline functions defined below.
|
|
||||||
*/
|
|
||||||
struct bbstreamer_ops
|
|
||||||
{
|
|
||||||
void (*content) (bbstreamer *streamer, bbstreamer_member *member,
|
|
||||||
const char *data, int len,
|
|
||||||
bbstreamer_archive_context context);
|
|
||||||
void (*finalize) (bbstreamer *streamer);
|
|
||||||
void (*free) (bbstreamer *streamer);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Send some content to a bbstreamer. */
|
|
||||||
static inline void
|
|
||||||
bbstreamer_content(bbstreamer *streamer, bbstreamer_member *member,
|
|
||||||
const char *data, int len,
|
|
||||||
bbstreamer_archive_context context)
|
|
||||||
{
|
|
||||||
Assert(streamer != NULL);
|
|
||||||
streamer->bbs_ops->content(streamer, member, data, len, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finalize a bbstreamer. */
|
|
||||||
static inline void
|
|
||||||
bbstreamer_finalize(bbstreamer *streamer)
|
|
||||||
{
|
|
||||||
Assert(streamer != NULL);
|
|
||||||
streamer->bbs_ops->finalize(streamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free a bbstreamer. */
|
|
||||||
static inline void
|
|
||||||
bbstreamer_free(bbstreamer *streamer)
|
|
||||||
{
|
|
||||||
Assert(streamer != NULL);
|
|
||||||
streamer->bbs_ops->free(streamer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a convenience method for use when implementing a bbstreamer; it is
|
|
||||||
* not for use by outside callers. It adds the amount of data specified by
|
|
||||||
* 'nbytes' to the bbstreamer's buffer and adjusts '*len' and '*data'
|
|
||||||
* accordingly.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
bbstreamer_buffer_bytes(bbstreamer *streamer, const char **data, int *len,
|
|
||||||
int nbytes)
|
|
||||||
{
|
|
||||||
Assert(nbytes <= *len);
|
|
||||||
|
|
||||||
appendBinaryStringInfo(&streamer->bbs_buffer, *data, nbytes);
|
|
||||||
*len -= nbytes;
|
|
||||||
*data += nbytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a convenience method for use when implementing a bbstreamer; it is
|
|
||||||
* not for use by outsider callers. It attempts to add enough data to the
|
|
||||||
* bbstreamer's buffer to reach a length of target_bytes and adjusts '*len'
|
|
||||||
* and '*data' accordingly. It returns true if the target length has been
|
|
||||||
* reached and false otherwise.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
bbstreamer_buffer_until(bbstreamer *streamer, const char **data, int *len,
|
|
||||||
int target_bytes)
|
|
||||||
{
|
|
||||||
int buflen = streamer->bbs_buffer.len;
|
|
||||||
|
|
||||||
if (buflen >= target_bytes)
|
|
||||||
{
|
|
||||||
/* Target length already reached; nothing to do. */
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buflen + *len < target_bytes)
|
|
||||||
{
|
|
||||||
/* Not enough data to reach target length; buffer all of it. */
|
|
||||||
bbstreamer_buffer_bytes(streamer, data, len, *len);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Buffer just enough to reach the target length. */
|
|
||||||
bbstreamer_buffer_bytes(streamer, data, len, target_bytes - buflen);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Functions for creating bbstreamer objects of various types. See the header
|
|
||||||
* comments for each of these functions for details.
|
|
||||||
*/
|
|
||||||
extern bbstreamer *bbstreamer_plain_writer_new(char *pathname, FILE *file);
|
|
||||||
extern bbstreamer *bbstreamer_gzip_writer_new(char *pathname, FILE *file,
|
|
||||||
pg_compress_specification *compress);
|
|
||||||
extern bbstreamer *bbstreamer_extractor_new(const char *basepath,
|
|
||||||
const char *(*link_map) (const char *),
|
|
||||||
void (*report_output_file) (const char *));
|
|
||||||
|
|
||||||
extern bbstreamer *bbstreamer_gzip_decompressor_new(bbstreamer *next);
|
|
||||||
extern bbstreamer *bbstreamer_lz4_compressor_new(bbstreamer *next,
|
|
||||||
pg_compress_specification *compress);
|
|
||||||
extern bbstreamer *bbstreamer_lz4_decompressor_new(bbstreamer *next);
|
|
||||||
extern bbstreamer *bbstreamer_zstd_compressor_new(bbstreamer *next,
|
|
||||||
pg_compress_specification *compress);
|
|
||||||
extern bbstreamer *bbstreamer_zstd_decompressor_new(bbstreamer *next);
|
|
||||||
extern bbstreamer *bbstreamer_tar_parser_new(bbstreamer *next);
|
|
||||||
extern bbstreamer *bbstreamer_tar_terminator_new(bbstreamer *next);
|
|
||||||
extern bbstreamer *bbstreamer_tar_archiver_new(bbstreamer *next);
|
|
||||||
|
|
||||||
extern bbstreamer *bbstreamer_recovery_injector_new(bbstreamer *next,
|
|
||||||
bool is_recovery_guc_supported,
|
|
||||||
PQExpBuffer recoveryconfcontents);
|
|
||||||
extern void bbstreamer_inject_file(bbstreamer *streamer, char *pathname,
|
|
||||||
char *data, int len);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,12 +1,12 @@
|
|||||||
# Copyright (c) 2022-2024, PostgreSQL Global Development Group
|
# Copyright (c) 2022-2024, PostgreSQL Global Development Group
|
||||||
|
|
||||||
common_sources = files(
|
common_sources = files(
|
||||||
'bbstreamer_file.c',
|
'astreamer_file.c',
|
||||||
'bbstreamer_gzip.c',
|
'astreamer_gzip.c',
|
||||||
'bbstreamer_inject.c',
|
'astreamer_inject.c',
|
||||||
'bbstreamer_lz4.c',
|
'astreamer_lz4.c',
|
||||||
'bbstreamer_tar.c',
|
'astreamer_tar.c',
|
||||||
'bbstreamer_zstd.c',
|
'astreamer_zstd.c',
|
||||||
'receivelog.c',
|
'receivelog.c',
|
||||||
'streamutil.c',
|
'streamutil.c',
|
||||||
'walmethods.c',
|
'walmethods.c',
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
# src/bin/pg_basebackup/nls.mk
|
# src/bin/pg_basebackup/nls.mk
|
||||||
CATALOG_NAME = pg_basebackup
|
CATALOG_NAME = pg_basebackup
|
||||||
GETTEXT_FILES = $(FRONTEND_COMMON_GETTEXT_FILES) \
|
GETTEXT_FILES = $(FRONTEND_COMMON_GETTEXT_FILES) \
|
||||||
bbstreamer_file.c \
|
astreamer_file.c \
|
||||||
bbstreamer_gzip.c \
|
astreamer_gzip.c \
|
||||||
bbstreamer_inject.c \
|
astreamer_inject.c \
|
||||||
bbstreamer_lz4.c \
|
astreamer_lz4.c \
|
||||||
bbstreamer_tar.c \
|
astreamer_tar.c \
|
||||||
bbstreamer_zstd.c \
|
astreamer_zstd.c \
|
||||||
pg_basebackup.c \
|
pg_basebackup.c \
|
||||||
pg_createsubscriber.c \
|
pg_createsubscriber.c \
|
||||||
pg_receivewal.c \
|
pg_receivewal.c \
|
||||||
|
@ -26,8 +26,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "access/xlog_internal.h"
|
#include "access/xlog_internal.h"
|
||||||
|
#include "astreamer.h"
|
||||||
#include "backup/basebackup.h"
|
#include "backup/basebackup.h"
|
||||||
#include "bbstreamer.h"
|
|
||||||
#include "common/compression.h"
|
#include "common/compression.h"
|
||||||
#include "common/file_perm.h"
|
#include "common/file_perm.h"
|
||||||
#include "common/file_utils.h"
|
#include "common/file_utils.h"
|
||||||
@ -57,8 +57,8 @@ typedef struct ArchiveStreamState
|
|||||||
{
|
{
|
||||||
int tablespacenum;
|
int tablespacenum;
|
||||||
pg_compress_specification *compress;
|
pg_compress_specification *compress;
|
||||||
bbstreamer *streamer;
|
astreamer *streamer;
|
||||||
bbstreamer *manifest_inject_streamer;
|
astreamer *manifest_inject_streamer;
|
||||||
PQExpBuffer manifest_buffer;
|
PQExpBuffer manifest_buffer;
|
||||||
char manifest_filename[MAXPGPATH];
|
char manifest_filename[MAXPGPATH];
|
||||||
FILE *manifest_file;
|
FILE *manifest_file;
|
||||||
@ -67,7 +67,7 @@ typedef struct ArchiveStreamState
|
|||||||
typedef struct WriteTarState
|
typedef struct WriteTarState
|
||||||
{
|
{
|
||||||
int tablespacenum;
|
int tablespacenum;
|
||||||
bbstreamer *streamer;
|
astreamer *streamer;
|
||||||
} WriteTarState;
|
} WriteTarState;
|
||||||
|
|
||||||
typedef struct WriteManifestState
|
typedef struct WriteManifestState
|
||||||
@ -199,8 +199,8 @@ static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *fo
|
|||||||
static void progress_update_filename(const char *filename);
|
static void progress_update_filename(const char *filename);
|
||||||
static void progress_report(int tablespacenum, bool force, bool finished);
|
static void progress_report(int tablespacenum, bool force, bool finished);
|
||||||
|
|
||||||
static bbstreamer *CreateBackupStreamer(char *archive_name, char *spclocation,
|
static astreamer *CreateBackupStreamer(char *archive_name, char *spclocation,
|
||||||
bbstreamer **manifest_inject_streamer_p,
|
astreamer **manifest_inject_streamer_p,
|
||||||
bool is_recovery_guc_supported,
|
bool is_recovery_guc_supported,
|
||||||
bool expect_unterminated_tarfile,
|
bool expect_unterminated_tarfile,
|
||||||
pg_compress_specification *compress);
|
pg_compress_specification *compress);
|
||||||
@ -1053,19 +1053,19 @@ ReceiveCopyData(PGconn *conn, WriteDataCallback callback,
|
|||||||
* the options selected by the user. We may just write the results directly
|
* the options selected by the user. We may just write the results directly
|
||||||
* to a file, or we might compress first, or we might extract the tar file
|
* to a file, or we might compress first, or we might extract the tar file
|
||||||
* and write each member separately. This function doesn't do any of that
|
* and write each member separately. This function doesn't do any of that
|
||||||
* directly, but it works out what kind of bbstreamer we need to create so
|
* directly, but it works out what kind of astreamer we need to create so
|
||||||
* that the right stuff happens when, down the road, we actually receive
|
* that the right stuff happens when, down the road, we actually receive
|
||||||
* the data.
|
* the data.
|
||||||
*/
|
*/
|
||||||
static bbstreamer *
|
static astreamer *
|
||||||
CreateBackupStreamer(char *archive_name, char *spclocation,
|
CreateBackupStreamer(char *archive_name, char *spclocation,
|
||||||
bbstreamer **manifest_inject_streamer_p,
|
astreamer **manifest_inject_streamer_p,
|
||||||
bool is_recovery_guc_supported,
|
bool is_recovery_guc_supported,
|
||||||
bool expect_unterminated_tarfile,
|
bool expect_unterminated_tarfile,
|
||||||
pg_compress_specification *compress)
|
pg_compress_specification *compress)
|
||||||
{
|
{
|
||||||
bbstreamer *streamer = NULL;
|
astreamer *streamer = NULL;
|
||||||
bbstreamer *manifest_inject_streamer = NULL;
|
astreamer *manifest_inject_streamer = NULL;
|
||||||
bool inject_manifest;
|
bool inject_manifest;
|
||||||
bool is_tar,
|
bool is_tar,
|
||||||
is_tar_gz,
|
is_tar_gz,
|
||||||
@ -1160,7 +1160,7 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
|
|||||||
directory = psprintf("%s/%s", basedir, spclocation);
|
directory = psprintf("%s/%s", basedir, spclocation);
|
||||||
else
|
else
|
||||||
directory = get_tablespace_mapping(spclocation);
|
directory = get_tablespace_mapping(spclocation);
|
||||||
streamer = bbstreamer_extractor_new(directory,
|
streamer = astreamer_extractor_new(directory,
|
||||||
get_tablespace_mapping,
|
get_tablespace_mapping,
|
||||||
progress_update_filename);
|
progress_update_filename);
|
||||||
}
|
}
|
||||||
@ -1188,27 +1188,27 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (compress->algorithm == PG_COMPRESSION_NONE)
|
if (compress->algorithm == PG_COMPRESSION_NONE)
|
||||||
streamer = bbstreamer_plain_writer_new(archive_filename,
|
streamer = astreamer_plain_writer_new(archive_filename,
|
||||||
archive_file);
|
archive_file);
|
||||||
else if (compress->algorithm == PG_COMPRESSION_GZIP)
|
else if (compress->algorithm == PG_COMPRESSION_GZIP)
|
||||||
{
|
{
|
||||||
strlcat(archive_filename, ".gz", sizeof(archive_filename));
|
strlcat(archive_filename, ".gz", sizeof(archive_filename));
|
||||||
streamer = bbstreamer_gzip_writer_new(archive_filename,
|
streamer = astreamer_gzip_writer_new(archive_filename,
|
||||||
archive_file, compress);
|
archive_file, compress);
|
||||||
}
|
}
|
||||||
else if (compress->algorithm == PG_COMPRESSION_LZ4)
|
else if (compress->algorithm == PG_COMPRESSION_LZ4)
|
||||||
{
|
{
|
||||||
strlcat(archive_filename, ".lz4", sizeof(archive_filename));
|
strlcat(archive_filename, ".lz4", sizeof(archive_filename));
|
||||||
streamer = bbstreamer_plain_writer_new(archive_filename,
|
streamer = astreamer_plain_writer_new(archive_filename,
|
||||||
archive_file);
|
archive_file);
|
||||||
streamer = bbstreamer_lz4_compressor_new(streamer, compress);
|
streamer = astreamer_lz4_compressor_new(streamer, compress);
|
||||||
}
|
}
|
||||||
else if (compress->algorithm == PG_COMPRESSION_ZSTD)
|
else if (compress->algorithm == PG_COMPRESSION_ZSTD)
|
||||||
{
|
{
|
||||||
strlcat(archive_filename, ".zst", sizeof(archive_filename));
|
strlcat(archive_filename, ".zst", sizeof(archive_filename));
|
||||||
streamer = bbstreamer_plain_writer_new(archive_filename,
|
streamer = astreamer_plain_writer_new(archive_filename,
|
||||||
archive_file);
|
archive_file);
|
||||||
streamer = bbstreamer_zstd_compressor_new(streamer, compress);
|
streamer = astreamer_zstd_compressor_new(streamer, compress);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1222,7 +1222,7 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
|
|||||||
* into it.
|
* into it.
|
||||||
*/
|
*/
|
||||||
if (must_parse_archive)
|
if (must_parse_archive)
|
||||||
streamer = bbstreamer_tar_archiver_new(streamer);
|
streamer = astreamer_tar_archiver_new(streamer);
|
||||||
progress_update_filename(archive_filename);
|
progress_update_filename(archive_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1241,7 +1241,7 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
|
|||||||
if (spclocation == NULL && writerecoveryconf)
|
if (spclocation == NULL && writerecoveryconf)
|
||||||
{
|
{
|
||||||
Assert(must_parse_archive);
|
Assert(must_parse_archive);
|
||||||
streamer = bbstreamer_recovery_injector_new(streamer,
|
streamer = astreamer_recovery_injector_new(streamer,
|
||||||
is_recovery_guc_supported,
|
is_recovery_guc_supported,
|
||||||
recoveryconfcontents);
|
recoveryconfcontents);
|
||||||
}
|
}
|
||||||
@ -1253,9 +1253,9 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
|
|||||||
* we're talking to such a server we'll need to add the terminator here.
|
* we're talking to such a server we'll need to add the terminator here.
|
||||||
*/
|
*/
|
||||||
if (must_parse_archive)
|
if (must_parse_archive)
|
||||||
streamer = bbstreamer_tar_parser_new(streamer);
|
streamer = astreamer_tar_parser_new(streamer);
|
||||||
else if (expect_unterminated_tarfile)
|
else if (expect_unterminated_tarfile)
|
||||||
streamer = bbstreamer_tar_terminator_new(streamer);
|
streamer = astreamer_tar_terminator_new(streamer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user has requested a server compressed archive along with
|
* If the user has requested a server compressed archive along with
|
||||||
@ -1264,11 +1264,11 @@ CreateBackupStreamer(char *archive_name, char *spclocation,
|
|||||||
if (format == 'p')
|
if (format == 'p')
|
||||||
{
|
{
|
||||||
if (is_tar_gz)
|
if (is_tar_gz)
|
||||||
streamer = bbstreamer_gzip_decompressor_new(streamer);
|
streamer = astreamer_gzip_decompressor_new(streamer);
|
||||||
else if (is_tar_lz4)
|
else if (is_tar_lz4)
|
||||||
streamer = bbstreamer_lz4_decompressor_new(streamer);
|
streamer = astreamer_lz4_decompressor_new(streamer);
|
||||||
else if (is_tar_zstd)
|
else if (is_tar_zstd)
|
||||||
streamer = bbstreamer_zstd_decompressor_new(streamer);
|
streamer = astreamer_zstd_decompressor_new(streamer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the results. */
|
/* Return the results. */
|
||||||
@ -1307,7 +1307,7 @@ ReceiveArchiveStream(PGconn *conn, pg_compress_specification *compress)
|
|||||||
if (state.manifest_inject_streamer != NULL &&
|
if (state.manifest_inject_streamer != NULL &&
|
||||||
state.manifest_buffer != NULL)
|
state.manifest_buffer != NULL)
|
||||||
{
|
{
|
||||||
bbstreamer_inject_file(state.manifest_inject_streamer,
|
astreamer_inject_file(state.manifest_inject_streamer,
|
||||||
"backup_manifest",
|
"backup_manifest",
|
||||||
state.manifest_buffer->data,
|
state.manifest_buffer->data,
|
||||||
state.manifest_buffer->len);
|
state.manifest_buffer->len);
|
||||||
@ -1318,8 +1318,8 @@ ReceiveArchiveStream(PGconn *conn, pg_compress_specification *compress)
|
|||||||
/* If there's still an archive in progress, end processing. */
|
/* If there's still an archive in progress, end processing. */
|
||||||
if (state.streamer != NULL)
|
if (state.streamer != NULL)
|
||||||
{
|
{
|
||||||
bbstreamer_finalize(state.streamer);
|
astreamer_finalize(state.streamer);
|
||||||
bbstreamer_free(state.streamer);
|
astreamer_free(state.streamer);
|
||||||
state.streamer = NULL;
|
state.streamer = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1383,8 +1383,8 @@ ReceiveArchiveStreamChunk(size_t r, char *copybuf, void *callback_data)
|
|||||||
/* End processing of any prior archive. */
|
/* End processing of any prior archive. */
|
||||||
if (state->streamer != NULL)
|
if (state->streamer != NULL)
|
||||||
{
|
{
|
||||||
bbstreamer_finalize(state->streamer);
|
astreamer_finalize(state->streamer);
|
||||||
bbstreamer_free(state->streamer);
|
astreamer_free(state->streamer);
|
||||||
state->streamer = NULL;
|
state->streamer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1437,8 +1437,8 @@ ReceiveArchiveStreamChunk(size_t r, char *copybuf, void *callback_data)
|
|||||||
else if (state->streamer != NULL)
|
else if (state->streamer != NULL)
|
||||||
{
|
{
|
||||||
/* Archive data. */
|
/* Archive data. */
|
||||||
bbstreamer_content(state->streamer, NULL, copybuf + 1,
|
astreamer_content(state->streamer, NULL, copybuf + 1,
|
||||||
r - 1, BBSTREAMER_UNKNOWN);
|
r - 1, ASTREAMER_UNKNOWN);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
pg_fatal("unexpected payload data");
|
pg_fatal("unexpected payload data");
|
||||||
@ -1600,7 +1600,7 @@ ReceiveTarFile(PGconn *conn, char *archive_name, char *spclocation,
|
|||||||
bool tablespacenum, pg_compress_specification *compress)
|
bool tablespacenum, pg_compress_specification *compress)
|
||||||
{
|
{
|
||||||
WriteTarState state;
|
WriteTarState state;
|
||||||
bbstreamer *manifest_inject_streamer;
|
astreamer *manifest_inject_streamer;
|
||||||
bool is_recovery_guc_supported;
|
bool is_recovery_guc_supported;
|
||||||
bool expect_unterminated_tarfile;
|
bool expect_unterminated_tarfile;
|
||||||
|
|
||||||
@ -1636,7 +1636,7 @@ ReceiveTarFile(PGconn *conn, char *archive_name, char *spclocation,
|
|||||||
pg_fatal("out of memory");
|
pg_fatal("out of memory");
|
||||||
|
|
||||||
/* Inject it into the output tarfile. */
|
/* Inject it into the output tarfile. */
|
||||||
bbstreamer_inject_file(manifest_inject_streamer, "backup_manifest",
|
astreamer_inject_file(manifest_inject_streamer, "backup_manifest",
|
||||||
buf.data, buf.len);
|
buf.data, buf.len);
|
||||||
|
|
||||||
/* Free memory. */
|
/* Free memory. */
|
||||||
@ -1644,8 +1644,8 @@ ReceiveTarFile(PGconn *conn, char *archive_name, char *spclocation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup. */
|
/* Cleanup. */
|
||||||
bbstreamer_finalize(state.streamer);
|
astreamer_finalize(state.streamer);
|
||||||
bbstreamer_free(state.streamer);
|
astreamer_free(state.streamer);
|
||||||
|
|
||||||
progress_report(tablespacenum, true, false);
|
progress_report(tablespacenum, true, false);
|
||||||
|
|
||||||
@ -1663,7 +1663,7 @@ ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data)
|
|||||||
{
|
{
|
||||||
WriteTarState *state = callback_data;
|
WriteTarState *state = callback_data;
|
||||||
|
|
||||||
bbstreamer_content(state->streamer, NULL, copybuf, r, BBSTREAMER_UNKNOWN);
|
astreamer_content(state->streamer, NULL, copybuf, r, ASTREAMER_UNKNOWN);
|
||||||
|
|
||||||
totaldone += r;
|
totaldone += r;
|
||||||
progress_report(state->tablespacenum, false, false);
|
progress_report(state->tablespacenum, false, false);
|
||||||
|
@ -3317,19 +3317,19 @@ bbsink_shell
|
|||||||
bbsink_state
|
bbsink_state
|
||||||
bbsink_throttle
|
bbsink_throttle
|
||||||
bbsink_zstd
|
bbsink_zstd
|
||||||
bbstreamer
|
astreamer
|
||||||
bbstreamer_archive_context
|
astreamer_archive_context
|
||||||
bbstreamer_extractor
|
astreamer_extractor
|
||||||
bbstreamer_gzip_decompressor
|
astreamer_gzip_decompressor
|
||||||
bbstreamer_gzip_writer
|
astreamer_gzip_writer
|
||||||
bbstreamer_lz4_frame
|
astreamer_lz4_frame
|
||||||
bbstreamer_member
|
astreamer_member
|
||||||
bbstreamer_ops
|
astreamer_ops
|
||||||
bbstreamer_plain_writer
|
astreamer_plain_writer
|
||||||
bbstreamer_recovery_injector
|
astreamer_recovery_injector
|
||||||
bbstreamer_tar_archiver
|
astreamer_tar_archiver
|
||||||
bbstreamer_tar_parser
|
astreamer_tar_parser
|
||||||
bbstreamer_zstd_frame
|
astreamer_zstd_frame
|
||||||
bgworker_main_type
|
bgworker_main_type
|
||||||
bh_node_type
|
bh_node_type
|
||||||
binaryheap
|
binaryheap
|
||||||
|
Reference in New Issue
Block a user