Skip to content

Commit 72cd834

Browse files
committed
Stream pkg_summary downloads via libarchive.
This splits download_summary() into an initialise function (sum_open()) and three archive_read_open() callbacks (sum_start(), sum_read(), sum_close()). libarchive can handle EOF and read failures, so this also simplifies things a little. One side-effect of this change is that we no longer need individual progress meters for the download and the database updates (in fact they would clash), so we now only use the libfetch progress meter. As we are now updating the database while the file is being fetched, if the fetch is incomplete we delete the remote summary database rather than leaving it in an inconsistent state. With these changes applied on 64-bit SmartOS we see a 2MB reduction in RSS usage, and a 1.5 second faster runtime for a fresh "pkgin update".
1 parent 0f5cdd1 commit 72cd834

File tree

4 files changed

+111
-104
lines changed

4 files changed

+111
-104
lines changed

download.c

Lines changed: 80 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,26 @@
3636
int fetchTimeout = 15; /* wait 15 seconds before timeout */
3737
size_t fetch_buffer = 1024;
3838

39-
Dlfile *
40-
download_summary(char *str_url, time_t *db_mtime)
39+
/*
40+
* Open a pkg_summary and if newer than local return an open libfetch
41+
* connection to it.
42+
*/
43+
Sumfile *
44+
sum_open(char *str_url, time_t *db_mtime)
4145
{
42-
/* from pkg_install/files/admin/audit.c */
43-
Dlfile *file;
44-
char *p;
45-
size_t buf_len, buf_fetched;
46-
ssize_t cur_fetched;
47-
off_t statsize;
48-
struct url_stat st;
49-
struct url *url;
50-
fetchIO *f = NULL;
46+
Sumfile *sum = NULL;
47+
fetchIO *f = NULL;
48+
struct url *url;
49+
struct url_stat st;
5150

5251
url = fetchParseURL(str_url);
5352

5453
if (url == NULL || (f = fetchXGet(url, &st, "")) == NULL)
55-
return NULL;
54+
goto nofetch;
5655

5756
if (st.size == -1) { /* could not obtain file size */
5857
*db_mtime = 0; /* not -1, don't force update */
59-
return NULL;
58+
goto nofetch;
6059
}
6160

6261
if (st.mtime <= *db_mtime) {
@@ -65,67 +64,99 @@ download_summary(char *str_url, time_t *db_mtime)
6564
* local summary up-to-date
6665
*/
6766
*db_mtime = -1;
68-
69-
fetchIO_close(f);
70-
71-
return NULL;
67+
goto nofetch;
7268
}
7369

7470
*db_mtime = st.mtime;
7571

76-
if ((p = strrchr(str_url, '/')) != NULL)
77-
p++;
78-
else
79-
p = (char *)str_url; /* should not happen */
80-
8172
#ifndef _MINIX /* XXX: SSIZE_MAX fails under MINIX */
8273
/* st.size is an off_t, it will be > SSIZE_MAX on 32 bits systems */
8374
if (sizeof(st.size) == sizeof(SSIZE_MAX) && st.size > SSIZE_MAX - 1)
8475
err(EXIT_FAILURE, "file is too large");
8576
#endif
8677

87-
buf_len = st.size;
88-
XMALLOC(file, sizeof(Dlfile));
89-
XMALLOC(file->buf, buf_len + 1);
78+
XMALLOC(sum, sizeof(Sumfile));
79+
80+
sum->fd = f;
81+
sum->url = url;
82+
sum->size = st.size;
83+
goto out;
84+
nofetch:
85+
if (url)
86+
fetchFreeURL(url);
87+
if (f)
88+
fetchIO_close(f);
89+
out:
90+
return sum;
91+
}
9092

91-
buf_fetched = 0;
92-
statsize = 0;
93+
/*
94+
* archive_read_open open callback. As we already have an open
95+
* libfetch handler all we need to do is print the download messages.
96+
*/
97+
int
98+
sum_start(struct archive *a, void *data)
99+
{
100+
Sumfile *sum = data;
101+
char *p;
93102

94103
if (!parsable) { /* human readable output */
104+
if ((p = strrchr(sum->url->doc, '/')) != NULL)
105+
p++;
106+
else
107+
p = (char *)sum->url->doc; /* should not happen */
108+
95109
printf(MSG_DOWNLOADING, p);
96110
fflush(stdout);
97-
98-
start_progress_meter(p, buf_len, &statsize);
111+
start_progress_meter(p, sum->size, &sum->pos);
99112
} else
100113
printf(MSG_DOWNLOAD_START);
101114

102-
while (buf_fetched < buf_len) {
103-
cur_fetched = fetchIO_read(f, file->buf + buf_fetched,
104-
fetch_buffer);
105-
if (cur_fetched == 0)
106-
errx(EXIT_FAILURE, "truncated file");
107-
else if (cur_fetched == -1)
108-
errx(EXIT_FAILURE, "failure during fetch of file: %s",
109-
fetchLastErrString);
110-
111-
buf_fetched += cur_fetched;
112-
statsize += cur_fetched;
113-
}
115+
return ARCHIVE_OK;
116+
}
117+
118+
/*
119+
* archive_read_open read callback. Read the next chunk of data from libfetch
120+
* and update the read position for the progress meter.
121+
*/
122+
ssize_t
123+
sum_read(struct archive *a, void *data, const void **buf)
124+
{
125+
Sumfile *sum = data;
126+
ssize_t fetched;
127+
128+
*buf = sum->buf;
129+
130+
fetched = fetchIO_read(sum->fd, sum->buf, sizeof(sum->buf));
131+
132+
if (fetched == -1)
133+
errx(EXIT_FAILURE, "failure during fetch of file: %s",
134+
fetchLastErrString);
135+
136+
sum->pos += fetched;
137+
138+
return fetched;
139+
}
140+
141+
/*
142+
* archive_read_open close callback. Stop the progress meter and close the
143+
* libfetch handler.
144+
*/
145+
int
146+
sum_close(struct archive *a, void *data)
147+
{
148+
Sumfile *sum = data;
114149

115150
if (!parsable)
116151
stop_progress_meter();
117152
else
118153
printf(MSG_DOWNLOAD_END);
119154

120-
file->buf[buf_len] = '\0';
121-
file->size = buf_len;
122-
123-
if (file->buf[0] == '\0')
124-
errx(EXIT_FAILURE, "empty download, exiting.\n");
125-
126-
fetchIO_close(f);
155+
fetchIO_close(sum->fd);
156+
fetchFreeURL(sum->url);
157+
XFREE(sum);
127158

128-
return file;
159+
return ARCHIVE_OK;
129160
}
130161

131162
/*

messages.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ in order to remove packages from the autoremove list, flag those with the `keep'
121121

122122
/* summary.c */
123123
#define MSG_READING_LOCAL_SUMMARY "reading local summary...\n"
124-
#define MSG_UPDATING_DB "updating database: 0%%"
125-
#define MSG_UPDATING_DB_PCT "\b\b\b\b%3d%%"
126124
#define MSG_CLEANING_DB_FROM_REPO "cleaning database from %s entries...\n"
127125
#define MSG_PROCESSING_LOCAL_SUMMARY "processing local summary...\n"
128126
#define MSG_DB_IS_UP_TO_DATE "database for %s is up-to-date\n"

pkgin.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
#include <sys/queue.h>
4141
#endif
4242

43+
#include <archive.h>
44+
#include <archive_entry.h>
4345
#include <fetch.h>
4446
#include <errno.h>
4547
#include "messages.h"
@@ -127,10 +129,17 @@
127129

128130
#define TRACE(fmt...) if (tracefp != NULL) fprintf(tracefp, fmt)
129131

130-
typedef struct Dlfile {
131-
char *buf;
132+
/**
133+
* \struct Sumfile
134+
* \brief Remote pkg_summary information
135+
*/
136+
typedef struct Sumfile {
137+
fetchIO *fd;
138+
struct url *url;
139+
char buf[65536];
132140
size_t size;
133-
} Dlfile;
141+
off_t pos;
142+
} Sumfile;
134143

135144
/**
136145
* \struct Deptree
@@ -227,7 +236,10 @@ extern FILE *tracefp;
227236
extern Preflist **preflist;
228237

229238
/* download.c*/
230-
Dlfile *download_summary(char *, time_t *);
239+
Sumfile *sum_open(char *, time_t *);
240+
int sum_start(struct archive *, void *);
241+
ssize_t sum_read(struct archive *, void *, const void **);
242+
int sum_close(struct archive *, void *);
231243
ssize_t download_pkg(char *, FILE *);
232244
/* summary.c */
233245
int update_db(int, char **);

summary.c

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@
3636

3737
#include "tools.h"
3838
#include "pkgin.h"
39-
#include <archive.h>
40-
#include <archive_entry.h>
4139

4240
static const struct Summary {
4341
const int type;
@@ -86,6 +84,7 @@ static void freecols(void);
8684
static void free_insertlist(void);
8785
static void insert_local_summary(FILE *);
8886
static void insert_remote_summary(struct archive *, char *);
87+
static void delete_remote_tbl(struct Summary, char *);
8988
static void prepare_insert(int, struct Summary);
9089
int colnames(void *, int, char **, char **);
9190

@@ -98,15 +97,14 @@ int force_fetch = 0;
9897
static const char *const sumexts[] = { "bz2", "gz", NULL };
9998

10099
/*
101-
* Download a remote summary into memory and return an open
102-
* libarchive handler to it.
100+
* Open a remote summary and return an open libarchive handler to it.
103101
*/
104102
static struct archive *
105103
fetch_summary(char *cur_repo)
106104
{
107105
struct archive *a;
108106
struct archive_entry *ae;
109-
Dlfile *file = NULL;
107+
Sumfile *sum = NULL;
110108
time_t sum_mtime;
111109
int i;
112110
char buf[BUFSIZ];
@@ -120,14 +118,14 @@ fetch_summary(char *cur_repo)
120118
snprintf(buf, BUFSIZ, "%s/%s.%s",
121119
cur_repo, PKG_SUMMARY, sumexts[i]);
122120

123-
if ((file = download_summary(buf, &sum_mtime)) != NULL)
121+
if ((sum = sum_open(buf, &sum_mtime)) != NULL)
124122
break; /* pkg_summary found and not up-to-date */
125123

126124
if (sum_mtime < 0) /* pkg_summary found, but up-to-date */
127125
return NULL;
128126
}
129127

130-
if (file == NULL)
128+
if (sum == NULL)
131129
errx(EXIT_FAILURE, MSG_COULDNT_FETCH, buf);
132130

133131
pkgindb_dovaquery(UPDATE_REPO_MTIME, (long long)sum_mtime, cur_repo);
@@ -137,35 +135,17 @@ fetch_summary(char *cur_repo)
137135

138136
if (archive_read_support_filter_all(a) != ARCHIVE_OK ||
139137
archive_read_support_format_raw(a) != ARCHIVE_OK ||
140-
archive_read_open_memory(a, file->buf, file->size) != ARCHIVE_OK)
141-
errx(EXIT_FAILURE, "Cannot open in-memory pkg_summary: %s",
138+
archive_read_open(a, sum, sum_start, sum_read, sum_close) != ARCHIVE_OK)
139+
errx(EXIT_FAILURE, "Cannot open pkg_summary: %s",
142140
archive_error_string(a));
143141

144142
if (archive_read_next_header(a, &ae) != ARCHIVE_OK)
145-
errx(EXIT_FAILURE, "Cannot read in-memory pkg_summary: %s",
143+
errx(EXIT_FAILURE, "Cannot read pkg_summary: %s",
146144
archive_error_string(a));
147145

148146
return a;
149147
}
150148

151-
/**
152-
* progress percentage
153-
*/
154-
static void
155-
progress(char c)
156-
{
157-
const char *alnum = ALNUM;
158-
int i, alnumlen = strlen(alnum);
159-
float percent = 0;
160-
161-
for (i = 0; i < alnumlen; i++)
162-
if (c == alnum[i])
163-
percent = ((float)(i + 1)/ (float)alnumlen) * 100;
164-
165-
printf(MSG_UPDATING_DB_PCT, (int)percent);
166-
fflush(stdout);
167-
}
168-
169149
static void
170150
freecols()
171151
{
@@ -278,11 +258,12 @@ parse_entry(struct Summary sum, int pkgid, char *line)
278258
if (check_machine_arch && strncmp(line, "MACHINE_ARCH=", 13) == 0) {
279259
if (strncmp(CHECK_MACHINE_ARCH, val,
280260
strlen(CHECK_MACHINE_ARCH))) {
261+
alarm(0); /* Stop the progress meter */
281262
printf(MSG_ARCH_DONT_MATCH, val, CHECK_MACHINE_ARCH);
282263
if (!check_yesno(DEFAULT_NO))
283264
exit(EXIT_FAILURE);
284265
check_machine_arch = 0;
285-
printf("\r"MSG_UPDATING_DB);
266+
alarm(1); /* Restart progress XXX: UPDATE_INTERVAL */
286267
}
287268
return;
288269
}
@@ -364,13 +345,6 @@ parse_entry(struct Summary sum, int pkgid, char *line)
364345
*v++ = '\0';
365346
add_to_slist("PKGNAME", val);
366347
add_to_slist("PKGVERS", v);
367-
368-
/*
369-
* Update progress counter based on position
370-
* in alphabet of first PKGNAME character.
371-
*/
372-
if (!parsable)
373-
progress(val[0]);
374348
} else
375349
add_to_slist(cols.name[i], val);
376350

@@ -451,11 +425,6 @@ insert_remote_summary(struct archive *a, char *cur_repo)
451425

452426
pkgindb_doquery("BEGIN;", NULL, NULL);
453427

454-
if (!parsable) {
455-
printf(MSG_UPDATING_DB);
456-
fflush(stdout);
457-
}
458-
459428
/*
460429
* Main loop. Read in archive, split into package records and parse
461430
* each entry, then insert packge. If we are in the middle of a
@@ -527,14 +496,11 @@ insert_remote_summary(struct archive *a, char *cur_repo)
527496

528497
pkgindb_doquery("COMMIT;", NULL, NULL);
529498

530-
if (!parsable) {
531-
printf("\n");
532-
fflush(stdout);
533-
}
534-
535-
if (r != ARCHIVE_OK)
499+
if (r != ARCHIVE_OK) {
500+
delete_remote_tbl(sumsw[REMOTE_SUMMARY], cur_repo);
536501
errx(EXIT_FAILURE, "Short read of pkg_summary: %s",
537502
archive_error_string(a));
503+
}
538504

539505
archive_read_close(a);
540506
}
@@ -685,6 +651,8 @@ update_remotedb(void)
685651
/* loop through PKG_REPOS */
686652
for (prepos = pkg_repos; *prepos != NULL; prepos++) {
687653

654+
printf(MSG_PROCESSING_REMOTE_SUMMARY, *prepos);
655+
688656
/* load remote pkg_summary */
689657
if ((a = fetch_summary(*prepos)) == NULL) {
690658
printf(MSG_DB_IS_UP_TO_DATE, *prepos);
@@ -701,8 +669,6 @@ update_remotedb(void)
701669
cleaned = 1;
702670
}
703671

704-
printf(MSG_PROCESSING_REMOTE_SUMMARY, *prepos);
705-
706672
/* delete remote* associated to this repository */
707673
delete_remote_tbl(sumsw[REMOTE_SUMMARY], *prepos);
708674
/* update remote* table for this repository */

0 commit comments

Comments
 (0)