log_archive.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: log__archive_8c-source.html,v 1.1 2008/06/08 10:20:14 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <errno.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <unistd.h>
00021 #endif
00022 
00023 #ifdef  HAVE_RPC
00024 #include "db_server.h"
00025 #endif
00026 
00027 #include "db_int.h"
00028 #include "db_dispatch.h"
00029 #include "log.h"
00030 
00031 #ifdef HAVE_RPC
00032 #include "gen_client_ext.h"
00033 #include "rpc_client_ext.h"
00034 #endif
00035 
00036 static int __absname __P((DB_ENV *, char *, char *, char **));
00037 static int __build_data __P((DB_ENV *, char *, char ***, void *(*)(size_t)));
00038 static int __cmpfunc __P((const void *, const void *));
00039 static int __usermem __P((DB_ENV *, char ***, void *(*)(size_t)));
00040 
00041 /*
00042  * CDB_log_archive --
00043  *      Supporting function for db_archive(1).
00044  */
00045 int
00046 CDB_log_archive(dbenv, listp, flags, db_malloc)
00047         DB_ENV *dbenv;
00048         char ***listp;
00049         u_int32_t flags;
00050         void *(*db_malloc) __P((size_t));
00051 {
00052         DBT rec;
00053         DB_LOG *dblp;
00054         DB_LSN stable_lsn;
00055         u_int32_t fnum;
00056         int array_size, n, ret;
00057         char **array, **arrayp, *name, *p, *pref, buf[MAXPATHLEN];
00058 
00059 #ifdef HAVE_RPC
00060         if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
00061                 return (__dbcl_log_archive(dbenv, listp, flags, db_malloc));
00062 #endif
00063 
00064         PANIC_CHECK(dbenv);
00065         ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG);
00066 
00067         name = NULL;
00068         dblp = dbenv->lg_handle;
00069         COMPQUIET(fnum, 0);
00070 
00071 #define OKFLAGS (DB_ARCH_ABS | DB_ARCH_DATA | DB_ARCH_LOG)
00072         if (flags != 0) {
00073                 if ((ret =
00074                     CDB___db_fchk(dbenv, "CDB_log_archive", flags, OKFLAGS)) != 0)
00075                         return (ret);
00076                 if ((ret =
00077                     CDB___db_fcchk(dbenv,
00078                         "CDB_log_archive", flags, DB_ARCH_DATA, DB_ARCH_LOG)) != 0)
00079                         return (ret);
00080         }
00081 
00082         /*
00083          * Get the absolute pathname of the current directory.  It would
00084          * be nice to get the shortest pathname of the database directory,
00085          * but that's just not possible.
00086          *
00087          * XXX
00088          * Can't trust getcwd(3) to set a valid errno.  If it doesn't, just
00089          * guess that we ran out of memory.
00090          */
00091         if (LF_ISSET(DB_ARCH_ABS)) {
00092                 CDB___os_set_errno(0);
00093                 if ((pref = getcwd(buf, sizeof(buf))) == NULL) {
00094                         if (CDB___os_get_errno() == 0)
00095                                 CDB___os_set_errno(ENOMEM);
00096                         return (CDB___os_get_errno());
00097                 }
00098         } else
00099                 pref = NULL;
00100 
00101         switch (LF_ISSET(~DB_ARCH_ABS)) {
00102         case DB_ARCH_DATA:
00103                 return (__build_data(dbenv, pref, listp, db_malloc));
00104         case DB_ARCH_LOG:
00105                 memset(&rec, 0, sizeof(rec));
00106                 if (F_ISSET(dbenv, DB_ENV_THREAD))
00107                         F_SET(&rec, DB_DBT_MALLOC);
00108                 if ((ret = CDB_log_get(dbenv, &stable_lsn, &rec, DB_LAST)) != 0)
00109                         return (ret);
00110                 if (F_ISSET(dbenv, DB_ENV_THREAD))
00111                         CDB___os_free(rec.data, rec.size);
00112                 fnum = stable_lsn.file;
00113                 break;
00114         case 0:
00115                 if ((ret = CDB___log_findckp(dbenv, &stable_lsn)) != 0) {
00116                         /*
00117                          * A return of DB_NOTFOUND means that we didn't find
00118                          * any records in the log (so we are not going to be
00119                          * deleting any log files).
00120                          */
00121                         if (ret != DB_NOTFOUND)
00122                                 return (ret);
00123                         *listp = NULL;
00124                         return (0);
00125                 }
00126                 /* Remove any log files before the last stable LSN. */
00127                 fnum = stable_lsn.file - 1;
00128                 break;
00129         }
00130 
00131 #define LIST_INCREMENT  64
00132         /* Get some initial space. */
00133         array_size = 10;
00134         if ((ret = CDB___os_malloc(dbenv,
00135             sizeof(char *) * array_size, NULL, &array)) != 0)
00136                 return (ret);
00137         array[0] = NULL;
00138 
00139         /* Build an array of the file names. */
00140         for (n = 0; fnum > 0; --fnum) {
00141                 if ((ret = CDB___log_name(dblp, fnum, &name, NULL, 0)) != 0)
00142                         goto err;
00143                 if (CDB___os_exists(name, NULL) != 0) {
00144                         if (LF_ISSET(DB_ARCH_LOG) && fnum == stable_lsn.file)
00145                                 continue;
00146                         CDB___os_freestr(name);
00147                         name = NULL;
00148                         break;
00149                 }
00150 
00151                 if (n >= array_size - 1) {
00152                         array_size += LIST_INCREMENT;
00153                         if ((ret = CDB___os_realloc(dbenv,
00154                             sizeof(char *) * array_size, NULL, &array)) != 0)
00155                                 goto err;
00156                 }
00157 
00158                 if (LF_ISSET(DB_ARCH_ABS)) {
00159                         if ((ret = __absname(dbenv,
00160                             pref, name, &array[n])) != 0)
00161                                 goto err;
00162                         CDB___os_freestr(name);
00163                 } else if ((p = CDB___db_rpath(name)) != NULL) {
00164                         if ((ret = CDB___os_strdup(dbenv, p + 1, &array[n])) != 0)
00165                                 goto err;
00166                         CDB___os_freestr(name);
00167                 } else
00168                         array[n] = name;
00169 
00170                 name = NULL;
00171                 array[++n] = NULL;
00172         }
00173 
00174         /* If there's nothing to return, we're done. */
00175         if (n == 0) {
00176                 *listp = NULL;
00177                 ret = 0;
00178                 goto err;
00179         }
00180 
00181         /* Sort the list. */
00182         qsort(array, (size_t)n, sizeof(char *), __cmpfunc);
00183 
00184         /* Rework the memory. */
00185         if ((ret = __usermem(dbenv, &array, db_malloc)) != 0)
00186                 goto err;
00187 
00188         *listp = array;
00189         return (0);
00190 
00191 err:    if (array != NULL) {
00192                 for (arrayp = array; *arrayp != NULL; ++arrayp)
00193                         CDB___os_freestr(*arrayp);
00194                 CDB___os_free(array, sizeof(char *) * array_size);
00195         }
00196         if (name != NULL)
00197                 CDB___os_freestr(name);
00198         return (ret);
00199 }
00200 
00201 /*
00202  * __build_data --
00203  *      Build a list of datafiles for return.
00204  */
00205 static int
00206 __build_data(dbenv, pref, listp, db_malloc)
00207         DB_ENV *dbenv;
00208         char *pref, ***listp;
00209         void *(*db_malloc) __P((size_t));
00210 {
00211         DBT rec;
00212         DB_LSN lsn;
00213         __log_register_args *argp;
00214         u_int32_t rectype;
00215         int array_size, last, n, nxt, ret;
00216         char **array, **arrayp, *p, *real_name;
00217 
00218         /* Get some initial space. */
00219         array_size = 10;
00220         if ((ret = CDB___os_malloc(dbenv,
00221             sizeof(char *) * array_size, NULL, &array)) != 0)
00222                 return (ret);
00223         array[0] = NULL;
00224 
00225         memset(&rec, 0, sizeof(rec));
00226         if (F_ISSET(dbenv, DB_ENV_THREAD))
00227                 F_SET(&rec, DB_DBT_MALLOC);
00228         for (n = 0, ret = CDB_log_get(dbenv, &lsn, &rec, DB_FIRST);
00229             ret == 0; ret = CDB_log_get(dbenv, &lsn, &rec, DB_NEXT)) {
00230                 if (rec.size < sizeof(rectype)) {
00231                         ret = EINVAL;
00232                         CDB___db_err(dbenv, "CDB_log_archive: bad log record");
00233                         goto lg_free;
00234                 }
00235 
00236                 memcpy(&rectype, rec.data, sizeof(rectype));
00237                 if (rectype != DB_log_register) {
00238                         if (F_ISSET(dbenv, DB_ENV_THREAD)) {
00239                                 CDB___os_free(rec.data, rec.size);
00240                                 rec.data = NULL;
00241                         }
00242                         continue;
00243                 }
00244                 if ((ret = CDB___log_register_read(dbenv, rec.data, &argp)) != 0) {
00245                         ret = EINVAL;
00246                         CDB___db_err(dbenv,
00247                             "CDB_log_archive: unable to read log record");
00248                         goto lg_free;
00249                 }
00250 
00251                 if (n >= array_size - 1) {
00252                         array_size += LIST_INCREMENT;
00253                         if ((ret = CDB___os_realloc(dbenv,
00254                             sizeof(char *) * array_size, NULL, &array)) != 0)
00255                                 goto lg_free;
00256                 }
00257 
00258                 if ((ret = CDB___os_strdup(dbenv,
00259                     argp->name.data, &array[n])) != 0) {
00260 lg_free:                if (F_ISSET(&rec, DB_DBT_MALLOC) && rec.data != NULL)
00261                                 CDB___os_free(rec.data, rec.size);
00262                         goto err1;
00263                 }
00264 
00265                 array[++n] = NULL;
00266                 CDB___os_free(argp, 0);
00267 
00268                 if (F_ISSET(dbenv, DB_ENV_THREAD)) {
00269                         CDB___os_free(rec.data, rec.size);
00270                         rec.data = NULL;
00271                 }
00272         }
00273 
00274         /* If there's nothing to return, we're done. */
00275         if (n == 0) {
00276                 ret = 0;
00277                 *listp = NULL;
00278                 goto err1;
00279         }
00280 
00281         /* Sort the list. */
00282         qsort(array, (size_t)n, sizeof(char *), __cmpfunc);
00283 
00284         /*
00285          * Build the real pathnames, discarding nonexistent files and
00286          * duplicates.
00287          */
00288         for (last = nxt = 0; nxt < n;) {
00289                 /*
00290                  * Discard duplicates.  Last is the next slot we're going
00291                  * to return to the user, nxt is the next slot that we're
00292                  * going to consider.
00293                  */
00294                 if (last != nxt) {
00295                         array[last] = array[nxt];
00296                         array[nxt] = NULL;
00297                 }
00298                 for (++nxt; nxt < n &&
00299                     strcmp(array[last], array[nxt]) == 0; ++nxt) {
00300                         CDB___os_freestr(array[nxt]);
00301                         array[nxt] = NULL;
00302                 }
00303 
00304                 /* Get the real name. */
00305                 if ((ret = CDB___db_appname(dbenv,
00306                     DB_APP_DATA, NULL, array[last], 0, NULL, &real_name)) != 0)
00307                         goto err2;
00308 
00309                 /* If the file doesn't exist, ignore it. */
00310                 if (CDB___os_exists(real_name, NULL) != 0) {
00311                         CDB___os_freestr(real_name);
00312                         CDB___os_freestr(array[last]);
00313                         array[last] = NULL;
00314                         continue;
00315                 }
00316 
00317                 /* Rework the name as requested by the user. */
00318                 CDB___os_freestr(array[last]);
00319                 array[last] = NULL;
00320                 if (pref != NULL) {
00321                         ret = __absname(dbenv, pref, real_name, &array[last]);
00322                         CDB___os_freestr(real_name);
00323                         if (ret != 0)
00324                                 goto err2;
00325                 } else if ((p = CDB___db_rpath(real_name)) != NULL) {
00326                         ret = CDB___os_strdup(dbenv, p + 1, &array[last]);
00327                         CDB___os_freestr(real_name);
00328                         if (ret != 0)
00329                                 goto err2;
00330                 } else
00331                         array[last] = real_name;
00332                 ++last;
00333         }
00334 
00335         /* NULL-terminate the list. */
00336         array[last] = NULL;
00337 
00338         /* Rework the memory. */
00339         if ((ret = __usermem(dbenv, &array, db_malloc)) != 0)
00340                 goto err1;
00341 
00342         *listp = array;
00343         return (0);
00344 
00345 err2:   /*
00346          * XXX
00347          * We've possibly inserted NULLs into the array list, so clean up a
00348          * bit so that the other error processing works.
00349          */
00350         if (array != NULL)
00351                 for (; nxt < n; ++nxt)
00352                         CDB___os_freestr(array[nxt]);
00353         /* FALLTHROUGH */
00354 
00355 err1:   if (array != NULL) {
00356                 for (arrayp = array; *arrayp != NULL; ++arrayp)
00357                         CDB___os_freestr(*arrayp);
00358                 CDB___os_free(array, array_size * sizeof(char *));
00359         }
00360         return (ret);
00361 }
00362 
00363 /*
00364  * __absname --
00365  *      Return an absolute path name for the file.
00366  */
00367 static int
00368 __absname(dbenv, pref, name, newnamep)
00369         DB_ENV *dbenv;
00370         char *pref, *name, **newnamep;
00371 {
00372         size_t l_pref, l_name;
00373         int isabspath, ret;
00374         char *newname;
00375 
00376         l_name = strlen(name);
00377         isabspath = CDB___os_abspath(name);
00378         l_pref = isabspath ? 0 : strlen(pref);
00379 
00380         /* Malloc space for concatenating the two. */
00381         if ((ret = CDB___os_malloc(dbenv,
00382             l_pref + l_name + 2, NULL, &newname)) != 0)
00383                 return (ret);
00384         *newnamep = newname;
00385 
00386         /* Build the name.  If `name' is an absolute path, ignore any prefix. */
00387         if (!isabspath) {
00388                 memcpy(newname, pref, l_pref);
00389                 if (strchr(PATH_SEPARATOR, newname[l_pref - 1]) == NULL)
00390                         newname[l_pref++] = PATH_SEPARATOR[0];
00391         }
00392         memcpy(newname + l_pref, name, l_name + 1);
00393 
00394         return (0);
00395 }
00396 
00397 /*
00398  * __usermem --
00399  *      Create a single chunk of memory that holds the returned information.
00400  *      If the user has their own malloc routine, use it.
00401  */
00402 static int
00403 __usermem(dbenv, listp, db_malloc)
00404         DB_ENV *dbenv;
00405         char ***listp;
00406         void *(*db_malloc) __P((size_t));
00407 {
00408         size_t len;
00409         int ret;
00410         char **array, **arrayp, **orig, *strp;
00411 
00412         /* Find out how much space we need. */
00413         for (len = 0, orig = *listp; *orig != NULL; ++orig)
00414                 len += sizeof(char *) + strlen(*orig) + 1;
00415         len += sizeof(char *);
00416 
00417         /* Allocate it and set up the pointers. */
00418         if ((ret = CDB___os_malloc(dbenv, len, db_malloc, &array)) != 0)
00419                 return (ret);
00420 
00421         strp = (char *)(array + (orig - *listp) + 1);
00422 
00423         /* Copy the original information into the new memory. */
00424         for (orig = *listp, arrayp = array; *orig != NULL; ++orig, ++arrayp) {
00425                 len = strlen(*orig);
00426                 memcpy(strp, *orig, len + 1);
00427                 *arrayp = strp;
00428                 strp += len + 1;
00429 
00430                 CDB___os_freestr(*orig);
00431         }
00432 
00433         /* NULL-terminate the list. */
00434         *arrayp = NULL;
00435 
00436         CDB___os_free(*listp, 0);
00437         *listp = array;
00438 
00439         return (0);
00440 }
00441 
00442 static int
00443 __cmpfunc(p1, p2)
00444         const void *p1, *p2;
00445 {
00446         return (strcmp(*((char * const *)p1), *((char * const *)p2)));
00447 }

Generated on Sun Jun 8 10:56:38 2008 for GNUmifluz by  doxygen 1.5.5