Update to db 2.3.10.
[kopensolaris-gnu/glibc.git] / db2 / progs / db_checkpoint / db_checkpoint.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997
5  *      Sleepycat Software.  All rights reserved.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char copyright[] =
12 "@(#) Copyright (c) 1997\n\
13         Sleepycat Software Inc.  All rights reserved.\n";
14 static const char sccsid[] = "@(#)db_checkpoint.c       10.12 (Sleepycat) 9/4/97";
15 #endif
16
17 #ifndef NO_SYSTEM_INCLUDES
18 #include <sys/types.h>
19
20 #include <errno.h>
21 #include <limits.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 #endif
29
30 #include "db_int.h"
31 #include "shqueue.h"
32 #include "db_page.h"
33 #include "log.h"
34 #include "btree.h"
35 #include "hash.h"
36 #include "clib_ext.h"
37 #include "common_ext.h"
38
39 char    *check __P((DB_ENV *, long, long));
40 int      checkpoint __P((DB_ENV *, char *, int));
41 DB_ENV  *db_init __P((char *));
42 int      logpid __P((char *, int));
43 int      main __P((int, char *[]));
44 void     onint __P((int));
45 void     siginit __P((void));
46 void     usage __P((void));
47
48 int      interrupted;
49 time_t   now;                                   /* Checkpoint time. */
50 const char
51         *progname = "db_checkpoint";            /* Program name. */
52
53 int
54 main(argc, argv)
55         int argc;
56         char *argv[];
57 {
58         extern char *optarg;
59         extern int optind;
60         DB_ENV *dbenv;
61         time_t now;
62         long kbytes, minutes, seconds;
63         int ch, eval, verbose;
64         char *home, *logfile;
65
66         home = logfile = NULL;
67         kbytes = minutes = 0;
68         verbose = 0;
69         while ((ch = getopt(argc, argv, "h:k:L:p:v")) != EOF)
70                 switch (ch) {
71                 case 'h':
72                         home = optarg;
73                         break;
74                 case 'k':
75                         get_long(optarg, 1, LONG_MAX, &kbytes);
76                         break;
77                 case 'L':
78                         logfile = optarg;
79                         break;
80                 case 'p':
81                         get_long(optarg, 1, LONG_MAX, &minutes);
82                         break;
83                 case 'v':
84                         verbose = 1;
85                         break;
86                 case '?':
87                 default:
88                         usage();
89                 }
90         argc -= optind;
91         argv += optind;
92
93         if (argc != 0)
94                 usage();
95
96         if (kbytes == 0 && minutes == 0) {
97                 warnx("at least one of -k and -p must be specified");
98                 usage();
99         }
100
101         /* Initialize the environment. */
102         dbenv = db_init(home);
103
104         if (logfile != NULL && logpid(logfile, 1)) {
105                 (void)db_appexit(dbenv);
106                 return (1);
107         }
108
109         /*
110          * If we have only a time delay, then we'll sleep the right amount
111          * to wake up when a checkpoint is necessary.  If we have a "kbytes"
112          * field set, then we'll check every 30 seconds.
113          */
114         eval = 0;
115         seconds = kbytes != 0 ? 30 : minutes * 60;
116         while (!interrupted) {
117                 (void)__db_sleep(seconds, 0);
118
119                 if (verbose) {
120                         (void)time(&now);
121                         printf("checkpoint: %s", ctime(&now));
122                 }
123                 errno = txn_checkpoint(dbenv->tx_info, kbytes, minutes);
124
125                 while (errno == DB_INCOMPLETE) {
126                         if (verbose)
127                                 __db_err(dbenv,
128                                     "checkpoint did not finish, retrying");
129                         (void)__db_sleep(2, 0);
130                         errno = txn_checkpoint(dbenv->tx_info, 0, 0);
131                 }
132
133                 if (errno != 0) {
134                         eval = 1;
135                         __db_err(dbenv, "checkpoint: %s", strerror(errno));
136                         break;
137                 }
138         }
139
140         if (logfile != NULL && logpid(logfile, 0))
141                 eval = 1;
142
143         if (interrupted) {
144                 (void)signal(interrupted, SIG_DFL);
145                 (void)raise(interrupted);
146                 /* NOTREACHED */
147         }
148
149         return (db_appexit(dbenv) || eval ? 1 : 0);
150 }
151
152 /*
153  * db_init --
154  *      Initialize the environment.
155  */
156 DB_ENV *
157 db_init(home)
158         char *home;
159 {
160         DB_ENV *dbenv;
161
162         if ((dbenv = (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) {
163                 errno = ENOMEM;
164                 err(1, NULL);
165         }
166         dbenv->db_errfile = stderr;
167         dbenv->db_errpfx = progname;
168
169         if ((errno = db_appinit(home, NULL, dbenv,
170            DB_INIT_LOG | DB_INIT_TXN | DB_INIT_MPOOL | DB_USE_ENVIRON)) != 0)
171                 err(1, "db_appinit");
172
173         if (memp_register(dbenv->mp_info,
174             DB_FTYPE_BTREE, __bam_pgin, __bam_pgout) ||
175             memp_register(dbenv->mp_info,
176             DB_FTYPE_HASH, __ham_pgin, __ham_pgout)) {
177                 (void)db_appexit(dbenv);
178                 errx(1,
179                     "db_appinit: failed to register access method functions");
180         }
181
182         siginit();
183
184         return (dbenv);
185 }
186
187 /*
188  * logpid --
189  *      Log that we're running.
190  */
191 int
192 logpid(fname, is_open)
193         char *fname;
194         int is_open;
195 {
196         FILE *fp;
197         time_t now;
198
199         if (is_open) {
200                 if ((fp = fopen(fname, "w")) == NULL) {
201                         warn("%s", fname);
202                         return (1);
203                 }
204                 (void)time(&now);
205                 fprintf(fp,
206                     "%s: %lu %s", progname, (u_long)getpid(), ctime(&now));
207                 fclose(fp);
208         } else
209                 (void)remove(fname);
210         return (0);
211 }
212
213 /*
214  * siginit --
215  *      Initialize the set of signals for which we want to clean up.
216  *      Generally, we try not to leave the shared regions locked if
217  *      we can.
218  */
219 void
220 siginit()
221 {
222 #ifdef SIGHUP
223         (void)signal(SIGHUP, onint);
224 #endif
225         (void)signal(SIGINT, onint);
226 #ifdef SIGKILL
227         (void)signal(SIGKILL, onint);
228 #endif
229         (void)signal(SIGTERM, onint);
230 }
231
232 /*
233  * oninit --
234  *      Interrupt signal handler.
235  */
236 void
237 onint(signo)
238         int signo;
239 {
240         if ((interrupted = signo) == 0)
241                 interrupted = SIGINT;
242 }
243
244 void
245 usage()
246 {
247         (void)fprintf(stderr,
248     "usage: db_checkpoint [-v] [-h home] [-k kbytes] [-L file] [-p min]\n");
249         exit(1);
250 }