~vlad-lesin/percona-server/mysql-5.0.33-original

« back to all changes in this revision

Viewing changes to bdb/log/log_archive.c

  • Committer: Vlad Lesin
  • Date: 2012-07-31 09:21:34 UTC
  • Revision ID: vladislav.lesin@percona.com-20120731092134-zfodx022b7992wsi
VirginĀ 5.0.33

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * See the file LICENSE for redistribution information.
 
3
 *
 
4
 * Copyright (c) 1997-2002
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
 
 
8
#include "db_config.h"
 
9
 
 
10
#ifndef lint
 
11
static const char revid[] = "$Id: log_archive.c,v 11.39 2002/08/06 05:00:31 bostic Exp $";
 
12
#endif /* not lint */
 
13
 
 
14
#ifndef NO_SYSTEM_INCLUDES
 
15
#include <sys/types.h>
 
16
 
 
17
#include <stdlib.h>
 
18
#include <string.h>
 
19
#include <unistd.h>
 
20
#endif
 
21
 
 
22
#include "db_int.h"
 
23
#include "dbinc/db_page.h"
 
24
#include "dbinc/log.h"
 
25
#include "dbinc/qam.h"
 
26
#include "dbinc/txn.h"
 
27
 
 
28
static int __absname __P((DB_ENV *, char *, char *, char **));
 
29
static int __build_data __P((DB_ENV *, char *, char ***));
 
30
static int __cmpfunc __P((const void *, const void *));
 
31
static int __usermem __P((DB_ENV *, char ***));
 
32
 
 
33
/*
 
34
 * __log_archive --
 
35
 *      Supporting function for db_archive(1).
 
36
 *
 
37
 * PUBLIC: int __log_archive __P((DB_ENV *, char **[], u_int32_t));
 
38
 */
 
39
int
 
40
__log_archive(dbenv, listp, flags)
 
41
        DB_ENV *dbenv;
 
42
        char ***listp;
 
43
        u_int32_t flags;
 
44
{
 
45
        DBT rec;
 
46
        DB_LOG *dblp;
 
47
        DB_LOGC *logc;
 
48
        DB_LSN stable_lsn;
 
49
        __txn_ckp_args *ckp_args;
 
50
        char **array, **arrayp, *name, *p, *pref, buf[MAXPATHLEN];
 
51
        int array_size, db_arch_abs, n, ret;
 
52
        u_int32_t fnum;
 
53
 
 
54
        PANIC_CHECK(dbenv);
 
55
        ENV_REQUIRES_CONFIG(dbenv,
 
56
            dbenv->lg_handle, "DB_ENV->log_archive", DB_INIT_LOG);
 
57
 
 
58
        name = NULL;
 
59
        dblp = dbenv->lg_handle;
 
60
        COMPQUIET(fnum, 0);
 
61
 
 
62
#define OKFLAGS (DB_ARCH_ABS | DB_ARCH_DATA | DB_ARCH_LOG)
 
63
        if (flags != 0) {
 
64
                if ((ret = __db_fchk(
 
65
                    dbenv, "DB_ENV->log_archive", flags, OKFLAGS)) != 0)
 
66
                        return (ret);
 
67
                if ((ret = __db_fcchk(dbenv, "DB_ENV->log_archive",
 
68
                    flags, DB_ARCH_DATA, DB_ARCH_LOG)) != 0)
 
69
                        return (ret);
 
70
        }
 
71
 
 
72
        if (LF_ISSET(DB_ARCH_ABS)) {
 
73
                db_arch_abs = 1;
 
74
                LF_CLR(DB_ARCH_ABS);
 
75
        } else
 
76
                db_arch_abs = 0;
 
77
 
 
78
        if (flags == 0 || flags == DB_ARCH_DATA)
 
79
                ENV_REQUIRES_CONFIG(dbenv,
 
80
                    dbenv->tx_handle, "DB_ENV->log_archive", DB_INIT_TXN);
 
81
 
 
82
        /*
 
83
         * Get the absolute pathname of the current directory.  It would
 
84
         * be nice to get the shortest pathname of the database directory,
 
85
         * but that's just not possible.
 
86
         *
 
87
         * XXX
 
88
         * Can't trust getcwd(3) to set a valid errno.  If it doesn't, just
 
89
         * guess that we ran out of memory.
 
90
         */
 
91
        if (db_arch_abs) {
 
92
                __os_set_errno(0);
 
93
                if ((pref = getcwd(buf, sizeof(buf))) == NULL) {
 
94
                        if (__os_get_errno() == 0)
 
95
                                __os_set_errno(ENOMEM);
 
96
                        return (__os_get_errno());
 
97
                }
 
98
        } else
 
99
                pref = NULL;
 
100
 
 
101
        switch (flags) {
 
102
        case DB_ARCH_DATA:
 
103
                return (__build_data(dbenv, pref, listp));
 
104
        case DB_ARCH_LOG:
 
105
                memset(&rec, 0, sizeof(rec));
 
106
                if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
 
107
                        return (ret);
 
108
#ifdef UMRW
 
109
                ZERO_LSN(stable_lsn);
 
110
#endif
 
111
                ret = logc->get(logc, &stable_lsn, &rec, DB_LAST);
 
112
                (void)logc->close(logc, 0);
 
113
                if (ret != 0)
 
114
                        return (ret);
 
115
                fnum = stable_lsn.file;
 
116
                break;
 
117
        case 0:
 
118
                memset(&rec, 0, sizeof(rec));
 
119
                if (__txn_getckp(dbenv, &stable_lsn) != 0) {
 
120
                        /*
 
121
                         * A failure return means that there's no checkpoint
 
122
                         * in the log (so we are not going to be deleting
 
123
                         * any log files).
 
124
                         */
 
125
                        *listp = NULL;
 
126
                        return (0);
 
127
                }
 
128
                if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
 
129
                        return (ret);
 
130
                if ((ret = logc->get(logc, &stable_lsn, &rec, DB_SET)) != 0 ||
 
131
                    (ret = __txn_ckp_read(dbenv, rec.data, &ckp_args)) != 0) {
 
132
                        /*
 
133
                         * A return of DB_NOTFOUND may only mean that the
 
134
                         * checkpoint LSN is before the beginning of the
 
135
                         * log files that we still have.  This is not
 
136
                         * an error;  it just means our work is done.
 
137
                         */
 
138
                        if (ret == DB_NOTFOUND) {
 
139
                                *listp = NULL;
 
140
                                ret = 0;
 
141
                        }
 
142
                        (void)logc->close(logc, 0);
 
143
                        return (ret);
 
144
                }
 
145
                if ((ret = logc->close(logc, 0)) != 0)
 
146
                        return (ret);
 
147
                stable_lsn = ckp_args->ckp_lsn;
 
148
                __os_free(dbenv, ckp_args);
 
149
 
 
150
                /* Remove any log files before the last stable LSN. */
 
151
                fnum = stable_lsn.file - 1;
 
152
                break;
 
153
        }
 
154
 
 
155
#define LIST_INCREMENT  64
 
156
        /* Get some initial space. */
 
157
        array_size = 64;
 
158
        if ((ret = __os_malloc(dbenv,
 
159
            sizeof(char *) * array_size, &array)) != 0)
 
160
                return (ret);
 
161
        array[0] = NULL;
 
162
 
 
163
        /* Build an array of the file names. */
 
164
        for (n = 0; fnum > 0; --fnum) {
 
165
                if ((ret = __log_name(dblp, fnum, &name, NULL, 0)) != 0)
 
166
                        goto err;
 
167
                if (__os_exists(name, NULL) != 0) {
 
168
                        if (LF_ISSET(DB_ARCH_LOG) && fnum == stable_lsn.file)
 
169
                                continue;
 
170
                        __os_free(dbenv, name);
 
171
                        name = NULL;
 
172
                        break;
 
173
                }
 
174
 
 
175
                if (n >= array_size - 2) {
 
176
                        array_size += LIST_INCREMENT;
 
177
                        if ((ret = __os_realloc(dbenv,
 
178
                            sizeof(char *) * array_size, &array)) != 0)
 
179
                                goto err;
 
180
                }
 
181
 
 
182
                if (db_arch_abs) {
 
183
                        if ((ret = __absname(dbenv,
 
184
                            pref, name, &array[n])) != 0)
 
185
                                goto err;
 
186
                        __os_free(dbenv, name);
 
187
                } else if ((p = __db_rpath(name)) != NULL) {
 
188
                        if ((ret = __os_strdup(dbenv, p + 1, &array[n])) != 0)
 
189
                                goto err;
 
190
                        __os_free(dbenv, name);
 
191
                } else
 
192
                        array[n] = name;
 
193
 
 
194
                name = NULL;
 
195
                array[++n] = NULL;
 
196
        }
 
197
 
 
198
        /* If there's nothing to return, we're done. */
 
199
        if (n == 0) {
 
200
                *listp = NULL;
 
201
                ret = 0;
 
202
                goto err;
 
203
        }
 
204
 
 
205
        /* Sort the list. */
 
206
        qsort(array, (size_t)n, sizeof(char *), __cmpfunc);
 
207
 
 
208
        /* Rework the memory. */
 
209
        if ((ret = __usermem(dbenv, &array)) != 0)
 
210
                goto err;
 
211
 
 
212
        *listp = array;
 
213
        return (0);
 
214
 
 
215
err:    if (array != NULL) {
 
216
                for (arrayp = array; *arrayp != NULL; ++arrayp)
 
217
                        __os_free(dbenv, *arrayp);
 
218
                __os_free(dbenv, array);
 
219
        }
 
220
        if (name != NULL)
 
221
                __os_free(dbenv, name);
 
222
        return (ret);
 
223
}
 
224
 
 
225
/*
 
226
 * __build_data --
 
227
 *      Build a list of datafiles for return.
 
228
 */
 
229
static int
 
230
__build_data(dbenv, pref, listp)
 
231
        DB_ENV *dbenv;
 
232
        char *pref, ***listp;
 
233
{
 
234
        DBT rec;
 
235
        DB_LOGC *logc;
 
236
        DB_LSN lsn;
 
237
        __dbreg_register_args *argp;
 
238
        u_int32_t rectype;
 
239
        int array_size, last, n, nxt, ret, t_ret;
 
240
        char **array, **arrayp, **list, **lp, *p, *real_name;
 
241
 
 
242
        /* Get some initial space. */
 
243
        array_size = 64;
 
244
        if ((ret = __os_malloc(dbenv,
 
245
            sizeof(char *) * array_size, &array)) != 0)
 
246
                return (ret);
 
247
        array[0] = NULL;
 
248
 
 
249
        memset(&rec, 0, sizeof(rec));
 
250
        if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
 
251
                return (ret);
 
252
        for (n = 0; (ret = logc->get(logc, &lsn, &rec, DB_PREV)) == 0;) {
 
253
                if (rec.size < sizeof(rectype)) {
 
254
                        ret = EINVAL;
 
255
                        __db_err(dbenv, "DB_ENV->log_archive: bad log record");
 
256
                        goto free_continue;
 
257
                }
 
258
 
 
259
                memcpy(&rectype, rec.data, sizeof(rectype));
 
260
                if (rectype != DB___dbreg_register)
 
261
                        continue;
 
262
                if ((ret =
 
263
                    __dbreg_register_read(dbenv, rec.data, &argp)) != 0) {
 
264
                        ret = EINVAL;
 
265
                        __db_err(dbenv,
 
266
                            "DB_ENV->log_archive: unable to read log record");
 
267
                        goto free_continue;
 
268
                }
 
269
 
 
270
                if (n >= array_size - 2) {
 
271
                        array_size += LIST_INCREMENT;
 
272
                        if ((ret = __os_realloc(dbenv,
 
273
                            sizeof(char *) * array_size, &array)) != 0)
 
274
                                goto free_continue;
 
275
                }
 
276
 
 
277
                if ((ret = __os_strdup(dbenv,
 
278
                    argp->name.data, &array[n++])) != 0)
 
279
                        goto free_continue;
 
280
                array[n] = NULL;
 
281
 
 
282
                if (argp->ftype == DB_QUEUE) {
 
283
                        if ((ret = __qam_extent_names(dbenv,
 
284
                            argp->name.data, &list)) != 0)
 
285
                                goto q_err;
 
286
                        for (lp = list;
 
287
                            lp != NULL && *lp != NULL; lp++) {
 
288
                                if (n >= array_size - 2) {
 
289
                                        array_size += LIST_INCREMENT;
 
290
                                        if ((ret = __os_realloc(dbenv,
 
291
                                            sizeof(char *) *
 
292
                                            array_size, &array)) != 0)
 
293
                                                goto q_err;
 
294
                                }
 
295
                                if ((ret =
 
296
                                    __os_strdup(dbenv, *lp, &array[n++])) != 0)
 
297
                                        goto q_err;
 
298
                                array[n] = NULL;
 
299
                        }
 
300
q_err:                  if (list != NULL)
 
301
                                __os_free(dbenv, list);
 
302
                }
 
303
free_continue:  __os_free(dbenv, argp);
 
304
                if (ret != 0)
 
305
                        break;
 
306
        }
 
307
        if (ret == DB_NOTFOUND)
 
308
                ret = 0;
 
309
        if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
 
310
                ret = t_ret;
 
311
        if (ret != 0)
 
312
                goto err1;
 
313
 
 
314
        /* If there's nothing to return, we're done. */
 
315
        if (n == 0) {
 
316
                ret = 0;
 
317
                *listp = NULL;
 
318
                goto err1;
 
319
        }
 
320
 
 
321
        /* Sort the list. */
 
322
        qsort(array, (size_t)n, sizeof(char *), __cmpfunc);
 
323
 
 
324
        /*
 
325
         * Build the real pathnames, discarding nonexistent files and
 
326
         * duplicates.
 
327
         */
 
328
        for (last = nxt = 0; nxt < n;) {
 
329
                /*
 
330
                 * Discard duplicates.  Last is the next slot we're going
 
331
                 * to return to the user, nxt is the next slot that we're
 
332
                 * going to consider.
 
333
                 */
 
334
                if (last != nxt) {
 
335
                        array[last] = array[nxt];
 
336
                        array[nxt] = NULL;
 
337
                }
 
338
                for (++nxt; nxt < n &&
 
339
                    strcmp(array[last], array[nxt]) == 0; ++nxt) {
 
340
                        __os_free(dbenv, array[nxt]);
 
341
                        array[nxt] = NULL;
 
342
                }
 
343
 
 
344
                /* Get the real name. */
 
345
                if ((ret = __db_appname(dbenv,
 
346
                    DB_APP_DATA, array[last], 0, NULL, &real_name)) != 0)
 
347
                        goto err2;
 
348
 
 
349
                /* If the file doesn't exist, ignore it. */
 
350
                if (__os_exists(real_name, NULL) != 0) {
 
351
                        __os_free(dbenv, real_name);
 
352
                        __os_free(dbenv, array[last]);
 
353
                        array[last] = NULL;
 
354
                        continue;
 
355
                }
 
356
 
 
357
                /* Rework the name as requested by the user. */
 
358
                __os_free(dbenv, array[last]);
 
359
                array[last] = NULL;
 
360
                if (pref != NULL) {
 
361
                        ret = __absname(dbenv, pref, real_name, &array[last]);
 
362
                        __os_free(dbenv, real_name);
 
363
                        if (ret != 0)
 
364
                                goto err2;
 
365
                } else if ((p = __db_rpath(real_name)) != NULL) {
 
366
                        ret = __os_strdup(dbenv, p + 1, &array[last]);
 
367
                        __os_free(dbenv, real_name);
 
368
                        if (ret != 0)
 
369
                                goto err2;
 
370
                } else
 
371
                        array[last] = real_name;
 
372
                ++last;
 
373
        }
 
374
 
 
375
        /* NULL-terminate the list. */
 
376
        array[last] = NULL;
 
377
 
 
378
        /* Rework the memory. */
 
379
        if ((ret = __usermem(dbenv, &array)) != 0)
 
380
                goto err1;
 
381
 
 
382
        *listp = array;
 
383
        return (0);
 
384
 
 
385
err2:   /*
 
386
         * XXX
 
387
         * We've possibly inserted NULLs into the array list, so clean up a
 
388
         * bit so that the other error processing works.
 
389
         */
 
390
        if (array != NULL)
 
391
                for (; nxt < n; ++nxt)
 
392
                        __os_free(dbenv, array[nxt]);
 
393
        /* FALLTHROUGH */
 
394
 
 
395
err1:   if (array != NULL) {
 
396
                for (arrayp = array; *arrayp != NULL; ++arrayp)
 
397
                        __os_free(dbenv, *arrayp);
 
398
                __os_free(dbenv, array);
 
399
        }
 
400
        return (ret);
 
401
}
 
402
 
 
403
/*
 
404
 * __absname --
 
405
 *      Return an absolute path name for the file.
 
406
 */
 
407
static int
 
408
__absname(dbenv, pref, name, newnamep)
 
409
        DB_ENV *dbenv;
 
410
        char *pref, *name, **newnamep;
 
411
{
 
412
        size_t l_pref, l_name;
 
413
        int isabspath, ret;
 
414
        char *newname;
 
415
 
 
416
        l_name = strlen(name);
 
417
        isabspath = __os_abspath(name);
 
418
        l_pref = isabspath ? 0 : strlen(pref);
 
419
 
 
420
        /* Malloc space for concatenating the two. */
 
421
        if ((ret = __os_malloc(dbenv,
 
422
            l_pref + l_name + 2, &newname)) != 0)
 
423
                return (ret);
 
424
        *newnamep = newname;
 
425
 
 
426
        /* Build the name.  If `name' is an absolute path, ignore any prefix. */
 
427
        if (!isabspath) {
 
428
                memcpy(newname, pref, l_pref);
 
429
                if (strchr(PATH_SEPARATOR, newname[l_pref - 1]) == NULL)
 
430
                        newname[l_pref++] = PATH_SEPARATOR[0];
 
431
        }
 
432
        memcpy(newname + l_pref, name, l_name + 1);
 
433
 
 
434
        return (0);
 
435
}
 
436
 
 
437
/*
 
438
 * __usermem --
 
439
 *      Create a single chunk of memory that holds the returned information.
 
440
 *      If the user has their own malloc routine, use it.
 
441
 */
 
442
static int
 
443
__usermem(dbenv, listp)
 
444
        DB_ENV *dbenv;
 
445
        char ***listp;
 
446
{
 
447
        size_t len;
 
448
        int ret;
 
449
        char **array, **arrayp, **orig, *strp;
 
450
 
 
451
        /* Find out how much space we need. */
 
452
        for (len = 0, orig = *listp; *orig != NULL; ++orig)
 
453
                len += sizeof(char *) + strlen(*orig) + 1;
 
454
        len += sizeof(char *);
 
455
 
 
456
        /* Allocate it and set up the pointers. */
 
457
        if ((ret = __os_umalloc(dbenv, len, &array)) != 0)
 
458
                return (ret);
 
459
 
 
460
        strp = (char *)(array + (orig - *listp) + 1);
 
461
 
 
462
        /* Copy the original information into the new memory. */
 
463
        for (orig = *listp, arrayp = array; *orig != NULL; ++orig, ++arrayp) {
 
464
                len = strlen(*orig);
 
465
                memcpy(strp, *orig, len + 1);
 
466
                *arrayp = strp;
 
467
                strp += len + 1;
 
468
 
 
469
                __os_free(dbenv, *orig);
 
470
        }
 
471
 
 
472
        /* NULL-terminate the list. */
 
473
        *arrayp = NULL;
 
474
 
 
475
        __os_free(dbenv, *listp);
 
476
        *listp = array;
 
477
 
 
478
        return (0);
 
479
}
 
480
 
 
481
static int
 
482
__cmpfunc(p1, p2)
 
483
        const void *p1, *p2;
 
484
{
 
485
        return (strcmp(*((char * const *)p1), *((char * const *)p2)));
 
486
}