Commit 9935066b authored by J.W. Schultz's avatar J.W. Schultz

Make idev, hlink and file_struct + strings use allocation

pools.
parent 6c2e5b56
......@@ -27,7 +27,7 @@ VERSION=@VERSION@
HEADERS=byteorder.h config.h errcode.h proto.h rsync.h
LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
lib/permstring.o @LIBOBJS@
lib/permstring.o lib/pool_alloc.o @LIBOBJS@
ZLIBOBJ=zlib/deflate.o zlib/infblock.o zlib/infcodes.o zlib/inffast.o \
zlib/inflate.o zlib/inftrees.o zlib/infutil.o zlib/trees.o \
zlib/zutil.o zlib/adler32.o
......
......@@ -100,6 +100,10 @@ Changes since 2.6.0:
* Less memory is used in the file list (a per-file savings).
* Changed hardlink info and file_struct + strings to use
allocation pools. This reduces memory use for large
filesets and permits freeing memory to the OS. (J.W. Schultz)
* The 2 pipes used between the receiver and generator processes
(which are forked on the same machine) were reduced to 1 pipe
and the protocol improved so that (1) it is now impossible to
......
......@@ -189,6 +189,7 @@ static int keep_backup(char *fname)
backup_dir[--backup_dir_len] = '\0';
if (verbose > 0)
rprintf(FINFO, "backup_dir is %s\n", backup_dir);
initialised = 1;
}
......@@ -199,7 +200,7 @@ static int keep_backup(char *fname)
if (do_stat(fname, &st)) return 1;
#endif
file = make_file(fname, NO_EXCLUDES);
file = make_file(fname, NULL, NO_EXCLUDES);
/* the file could have disappeared */
if (!file) return 1;
......@@ -282,7 +283,7 @@ static int keep_backup(char *fname)
}
}
set_perms(keep_name, file, NULL, 0);
free_file(file, FREE_STRUCT);
free(file);
if (verbose > 1)
rprintf(FINFO, "keep_backup %s -> %s\n", fname, keep_name);
......
......@@ -136,9 +136,7 @@ struct file_list *create_flist_from_batch(void)
exit_cleanup(1);
}
batch_flist = new(struct file_list);
if (!batch_flist)
out_of_memory("create_flist_from_batch");
batch_flist = flist_new(WITH_HLINK, "create_flist_from_batch");
save_read = stats.total_read;
save_pv = protocol_version;
......@@ -150,9 +148,9 @@ struct file_list *create_flist_from_batch(void)
for (i = 0; (flags = read_byte(f)) != 0; i++) {
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
receive_file_entry(&batch_flist->files[i], flags, f);
receive_file_entry(&batch_flist->files[i], flags, batch_flist, f);
}
receive_file_entry(NULL, 0, 0); /* Signal that we're done. */
receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
protocol_version = save_pv;
stats.total_read = save_read;
......
......@@ -71,18 +71,17 @@ extern struct exclude_struct **local_exclude_list;
int io_error;
static char empty_sum[MD4_SUM_LENGTH];
static unsigned int min_file_struct_len;
static unsigned int file_struct_len;
static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
static void output_flist(struct file_list *flist);
void init_flist(void)
{
struct file_struct f;
/* Figure out how big the file_struct is without trailing padding */
min_file_struct_len = ((char*)&f.flags - (char*)&f) + sizeof f.flags;
file_struct_len = ((char*)&f.flags - (char*)&f) + sizeof f.flags;
}
......@@ -507,7 +506,8 @@ void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
void receive_file_entry(struct file_struct **fptr, unsigned short flags,
struct file_list *flist, int f)
{
static time_t modtime;
static mode_t mode;
......@@ -520,7 +520,6 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
char thisname[MAXPATHLEN];
unsigned int l1 = 0, l2 = 0;
int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
int file_struct_len, idev_len;
OFF_T file_length;
char *basename, *dirname, *bp;
struct file_struct *file;
......@@ -614,24 +613,14 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
#endif
linkname_len = 0;
#if SUPPORT_HARD_LINKS
if (preserve_hard_links && protocol_version < 28 && S_ISREG(mode))
flags |= XMIT_HAS_IDEV_DATA;
if (flags & XMIT_HAS_IDEV_DATA)
idev_len = sizeof (struct idev);
else
#endif
idev_len = 0;
sum_len = always_checksum && S_ISREG(mode) ? MD4_SUM_LENGTH : 0;
file_struct_len = idev_len? sizeof file[0] : min_file_struct_len;
alloc_len = file_struct_len + dirname_len + basename_len
+ linkname_len + sum_len + idev_len;
if (!(bp = new_array(char, alloc_len)))
out_of_memory("receive_file_entry");
+ linkname_len + sum_len;
bp = pool_alloc(flist->file_pool, alloc_len, "receive_file_entry");
file = *fptr = (struct file_struct *)bp;
memset(bp, 0, min_file_struct_len);
memset(bp, 0, file_struct_len);
bp += file_struct_len;
file->flags = flags & XMIT_TOP_DIR ? FLAG_TOP_DIR : 0;
......@@ -641,13 +630,6 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
file->uid = uid;
file->gid = gid;
#if SUPPORT_HARD_LINKS
if (idev_len) {
file->link_u.idev = (struct idev *)bp;
bp += idev_len;
}
#endif
if (dirname_len) {
file->dirname = lastdir = bp;
lastdir_len = dirname_len - 1;
......@@ -675,16 +657,24 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
#endif
#if SUPPORT_HARD_LINKS
if (idev_len) {
if (preserve_hard_links && protocol_version < 28 && S_ISREG(mode))
flags |= XMIT_HAS_IDEV_DATA;
if (flags & XMIT_HAS_IDEV_DATA && flist->hlink_pool) {
INO64_T inode;
file->link_u.idev = pool_talloc(flist->hlink_pool,
struct idev, 1, "inode_table");
if (protocol_version < 26) {
dev = read_int(f);
file->F_INODE = read_int(f);
inode = read_int(f);
} else {
if (!(flags & XMIT_SAME_DEV))
dev = read_longint(f);
file->F_INODE = read_longint(f);
inode = read_longint(f);
}
if (flist->hlink_pool) {
file->F_INODE = inode;
file->F_DEV = dev;
}
file->F_DEV = dev;
}
#endif
......@@ -728,7 +718,8 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
* statting directories if we're not recursing, but this is not a very
* important case. Some systems may not have d_type.
**/
struct file_struct *make_file(char *fname, int exclude_level)
struct file_struct *make_file(char *fname,
struct file_list *flist, int exclude_level)
{
static char *lastdir;
static int lastdir_len = -1;
......@@ -738,10 +729,10 @@ struct file_struct *make_file(char *fname, int exclude_level)
char thisname[MAXPATHLEN];
char linkname[MAXPATHLEN];
int alloc_len, basename_len, dirname_len, linkname_len, sum_len;
int file_struct_len, idev_len;
char *basename, *dirname, *bp;
unsigned short flags = 0;
if (strlcpy(thisname, fname, sizeof thisname)
>= sizeof thisname - flist_dir_len) {
rprintf(FINFO, "skipping overly long name: %s\n", fname);
......@@ -820,32 +811,20 @@ struct file_struct *make_file(char *fname, int exclude_level)
linkname_len = 0;
#endif
#if SUPPORT_HARD_LINKS
if (preserve_hard_links) {
if (protocol_version < 28) {
if (S_ISREG(st.st_mode))
idev_len = sizeof (struct idev);
else
idev_len = 0;
} else {
if (!S_ISDIR(st.st_mode) && st.st_nlink > 1)
idev_len = sizeof (struct idev);
else
idev_len = 0;
}
} else
#endif
idev_len = 0;
sum_len = always_checksum && S_ISREG(st.st_mode) ? MD4_SUM_LENGTH : 0;
file_struct_len = idev_len? sizeof file[0] : min_file_struct_len;
alloc_len = file_struct_len + dirname_len + basename_len
+ linkname_len + sum_len + idev_len;
if (!(bp = new_array(char, alloc_len)))
out_of_memory("receive_file_entry");
+ linkname_len + sum_len;
if (flist) {
bp = pool_alloc(flist->file_pool, alloc_len,
"receive_file_entry");
} else {
if (!(bp = new_array(char, alloc_len)))
out_of_memory("receive_file_entry");
}
file = (struct file_struct *)bp;
memset(bp, 0, min_file_struct_len);
memset(bp, 0, file_struct_len);
bp += file_struct_len;
file->flags = flags;
......@@ -856,9 +835,20 @@ struct file_struct *make_file(char *fname, int exclude_level)
file->gid = st.st_gid;
#if SUPPORT_HARD_LINKS
if (idev_len) {
file->link_u.idev = (struct idev *)bp;
bp += idev_len;
if (flist && flist->hlink_pool) {
if (protocol_version < 28) {
if (S_ISREG(st.st_mode))
file->link_u.idev = pool_talloc(
flist->hlink_pool, struct idev, 1,
"inode_table");
} else {
if (!S_ISDIR(st.st_mode) && st.st_nlink > 1)
file->link_u.idev = pool_talloc(
flist->hlink_pool, struct idev, 1,
"inode_table");
}
}
if (file->link_u.idev) {
file->F_DEV = st.st_dev;
file->F_INODE = st.st_ino;
}
......@@ -913,9 +903,8 @@ void send_file_name(int f, struct file_list *flist, char *fname,
extern int delete_excluded;
/* f is set to -1 when calculating deletion file list */
file = make_file(fname,
f == -1 && delete_excluded? SERVER_EXCLUDES
: ALL_EXCLUDES);
file = make_file(fname, flist,
f == -1 && delete_excluded? SERVER_EXCLUDES : ALL_EXCLUDES);
if (!file)
return;
......@@ -1034,7 +1023,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
start_write = stats.total_written;
flist = flist_new();
flist = flist_new(f == -1 ? WITHOUT_HLINK : WITH_HLINK,
"send_file_list");
if (f != -1) {
io_start_buffering_out(f);
......@@ -1185,6 +1175,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
finish_filelist_progress(flist);
}
if (flist->hlink_pool)
{
pool_destroy(flist->hlink_pool);
flist->hlink_pool = NULL;
}
clean_flist(flist, 0, 0);
if (f != -1) {
......@@ -1224,9 +1220,7 @@ struct file_list *recv_file_list(int f)
start_read = stats.total_read;
flist = new(struct file_list);
if (!flist)
goto oom;
flist = flist_new(WITH_HLINK, "recv_file_list");
flist->count = 0;
flist->malloced = 1000;
......@@ -1242,7 +1236,7 @@ struct file_list *recv_file_list(int f)
if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
flags |= read_byte(f) << 8;
receive_file_entry(&flist->files[i], flags, f);
receive_file_entry(&flist->files[i], flags, flist, f);
if (S_ISREG(flist->files[i]->mode))
stats.total_size += flist->files[i]->length;
......@@ -1256,7 +1250,7 @@ struct file_list *recv_file_list(int f)
f_name(flist->files[i]));
}
}
receive_file_entry(NULL, 0, 0); /* Signal that we're done. */
receive_file_entry(NULL, 0, NULL, 0); /* Signal that we're done. */
if (verbose > 2)
rprintf(FINFO, "received %d names\n", flist->count);
......@@ -1345,34 +1339,42 @@ int flist_find(struct file_list *flist, struct file_struct *f)
return -1;
}
/*
* Free up any resources a file_struct has allocated, and optionally free
* it up as well.
* Free up any resources a file_struct has allocated
* and clear the file.
*/
void free_file(struct file_struct *file, int free_the_struct)
void clear_file(int i, struct file_list *flist)
{
if (free_the_struct)
free(file);
else
memset(file, 0, min_file_struct_len);
if (flist->hlink_pool && flist->files[i]->link_u.idev)
pool_free(flist->hlink_pool, 0, flist->files[i]->link_u.idev);
memset(flist->files[i], 0, file_struct_len);
}
/*
* allocate a new file list
*/
struct file_list *flist_new(void)
struct file_list *flist_new(int with_hlink, char *msg)
{
struct file_list *flist;
flist = new(struct file_list);
if (!flist)
out_of_memory("send_file_list");
out_of_memory(msg);
flist->count = 0;
flist->malloced = 0;
flist->files = NULL;
memset(flist, 0, sizeof (struct file_list));
if (!(flist->file_pool = pool_create(FILE_EXTENT, 0,
out_of_memory, POOL_INTERN)))
out_of_memory(msg);
#if SUPPORT_HARD_LINKS
if (with_hlink && preserve_hard_links) {
if (!(flist->hlink_pool = pool_create(HLINK_EXTENT,
sizeof (struct idev), out_of_memory, POOL_INTERN)))
out_of_memory(msg);
}
#endif
return flist;
}
......@@ -1382,9 +1384,8 @@ struct file_list *flist_new(void)
*/
void flist_free(struct file_list *flist)
{
int i;
for (i = 1; i < flist->count; i++)
free_file(flist->files[i], FREE_STRUCT);
pool_destroy(flist->file_pool);
pool_destroy(flist->hlink_pool);
free(flist->files);
free(flist);
}
......@@ -1424,7 +1425,8 @@ static void clean_flist(struct file_list *flist, int strip_root, int no_dups)
* else deletions will mysteriously fail with -R). */
if (flist->files[i]->flags & FLAG_TOP_DIR)
flist->files[prev_i]->flags |= FLAG_TOP_DIR;
free_file(flist->files[i], CLEAR_STRUCT);
clear_file(i, flist);
} else
prev_i = i;
}
......
......@@ -46,26 +46,41 @@ int hlink_count;
/* Analyze the data in the hlink_list[], remove items that aren't multiply
* linked, and replace the dev+inode data with the hlindex+next linked list. */
static void link_idev_data(void)
static void link_idev_data(struct file_list *flist)
{
struct file_struct *head;
int from, to, start;
alloc_pool_t hlink_pool;
alloc_pool_t idev_pool = flist->hlink_pool;
hlink_pool = pool_create(128 * 1024, sizeof (struct hlink),
out_of_memory, POOL_INTERN);
for (from = to = 0; from < hlink_count; from++) {
start = from;
head = hlink_list[start];
while (from < hlink_count-1
&& LINKED(hlink_list[from], hlink_list[from+1])) {
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
struct hlink, 1, "hlink_list");
hlink_list[from]->F_HLINDEX = to;
hlink_list[from]->F_NEXT = hlink_list[from+1];
from++;
}
if (from > start) {
pool_free(idev_pool, 0, hlink_list[from]->link_u.idev);
hlink_list[from]->link_u.links = pool_talloc(hlink_pool,
struct hlink, 1, "hlink_list");
hlink_list[from]->F_HLINDEX = to;
hlink_list[from]->F_NEXT = head;
hlink_list[from]->flags |= FLAG_HLINK_EOL;
hlink_list[to++] = head;
} else {
pool_free(idev_pool, 0, head->link_u.idev);
head->link_u.idev = NULL;
}
}
......@@ -73,12 +88,16 @@ static void link_idev_data(void)
if (!to) {
free(hlink_list);
hlink_list = NULL;
pool_destroy(hlink_pool);
hlink_pool = NULL;
} else {
hlink_count = to;
if (!(hlink_list = realloc_array(hlink_list,
struct file_struct *, hlink_count)))
out_of_memory("init_hard_links");
}
flist->hlink_pool = hlink_pool;
pool_destroy(idev_pool);
}
#endif
......@@ -109,7 +128,7 @@ void init_hard_links(struct file_list *flist)
free(hlink_list);
hlink_list = NULL;
} else
link_idev_data();
link_idev_data(flist);
#endif
}
......
......@@ -305,6 +305,12 @@ int recv_files(int f_in,struct file_list *flist,char *local_name)
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
if (flist->hlink_pool)
{
pool_destroy(flist->hlink_pool);
flist->hlink_pool = NULL;
}
while (1) {
cleanup_disable();
......
......@@ -112,8 +112,6 @@
#define FULL_FLUSH 1
#define NORMAL_FLUSH 0
#define CLEAR_STRUCT 0
#define FREE_STRUCT 1
/* Log-message categories. FLOG is only used on the daemon side to
* output messages to the log file. */
......@@ -254,6 +252,7 @@ enum msgcode {
#include <assert.h>
#include "lib/pool_alloc.h"
#define BOOL int
......@@ -434,10 +433,27 @@ struct file_struct {
*/
#define FLIST_START (32 * 1024)
#define FLIST_LINEAR (FLIST_START * 512)
/*
* Extent size for allocation pools A minimum size of 128KB
* is needed to mmap them so that freeing will release the
* space to the OS.
*
* Larger sizes reduce leftover fragments and speed free calls
* (when they happen) Smaller sizes increase the chance of
* freed allocations freeing whole extents.
*/
#define FILE_EXTENT (256 * 1024)
#define HLINK_EXTENT (128 * 1024)
#define WITH_HLINK 1
#define WITHOUT_HLINK 0
struct file_list {
int count;
int malloced;
alloc_pool_t file_pool;
alloc_pool_t hlink_pool;
struct file_struct **files;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment