]> andersk Git - moira.git/blame - server/increment.pc
if the server is SLEEPY (got a SIGUSR1), close the database the next
[moira.git] / server / increment.pc
CommitLineData
7ac48069 1/* $Id$
32cfe906 2 *
7ac48069 3 * Deal with incremental updates
5eaef520 4 *
7ac48069 5 * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
32cfe906 8 */
9
32cfe906 10#include <mit-copyright.h>
32cfe906 11#include "mr_server.h"
03c05291 12#include "query.h"
13#include "qrtn.h"
7ac48069 14
15#include <signal.h>
85330553 16#include <stdio.h>
7ac48069 17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20
45bf7573 21EXEC SQL INCLUDE sqlca;
32cfe906 22
7ac48069 23RCSID("$Header$");
24
32cfe906 25extern char *whoami;
03c05291 26extern char *table_name[];
27extern int num_tables;
32cfe906 28
29int inc_pid = 0;
30int inc_running = 0;
31time_t inc_started;
32
33#define MAXARGC 15
34
03c05291 35EXEC SQL WHENEVER SQLERROR DO dbmserr();
45bf7573 36
32cfe906 37/* structures to save before args */
32cfe906 38static char *before[MAXARGC];
32cfe906 39static int beforec;
03c05291 40static enum tables beforetable;
32cfe906 41
42/* structures to save after args */
32cfe906 43static char *after[MAXARGC];
32cfe906 44static int afterc;
45
46/* structures to save entire sets of incremental changes */
47struct save_queue *incremental_sq = NULL;
48struct save_queue *incremental_exec = NULL;
49struct iupdate {
5eaef520 50 char *table;
51 int beforec;
52 char **before;
53 int afterc;
54 char **after;
55 char *service;
32cfe906 56};
57
03c05291 58void next_incremental(void);
03c05291 59void free_argv(char **argv, int argc);
60int table_num(char *table);
32cfe906 61
03c05291 62void incremental_init(void)
32cfe906 63{
5eaef520 64 int i;
32cfe906 65
5eaef520 66 if (!incremental_sq)
67 incremental_sq = sq_create();
68 if (!incremental_exec)
69 incremental_exec = sq_create();
03c05291 70
5eaef520 71 for (i = 0; i < MAXARGC; i++)
72 {
e688520a 73 before[i] = xmalloc(MAX_FIELD_WIDTH);
74 after[i] = xmalloc(MAX_FIELD_WIDTH);
03c05291 75 }
32cfe906 76}
77
78
03c05291 79/* record the state of a table row before it is changed */
80
5eaef520 81void incremental_before(enum tables table, char *qual, char **argv)
32cfe906 82{
5eaef520 83 EXEC SQL BEGIN DECLARE SECTION;
84 int id;
85 EXEC SQL END DECLARE SECTION;
86
87 char *name;
88
89 beforetable = table;
90
91 switch (table)
92 {
93 case USERS_TABLE:
94 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
95 "u.first, u.middle, u.status, u.clearid, u.type "
96 "FROM users u WHERE %s", qual);
97 dosql(before);
98 beforec = 9;
99 break;
100 case MACHINE_TABLE:
101 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
102 "WHERE %s", qual);
103 dosql(before);
104 beforec = 2;
105 break;
e688520a 106 case CLUSTERS_TABLE:
5eaef520 107 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
108 "FROM clusters c WHERE %s", qual);
109 dosql(before);
110 beforec = 3;
111 break;
112 case MCMAP_TABLE:
113 strcpy(before[0], argv[0]);
114 strcpy(before[1], argv[1]);
115 beforec = 2;
116 break;
117 case SVC_TABLE:
118 strcpy(before[0], argv[0]);
119 strcpy(before[1], argv[1]);
120 strcpy(before[2], argv[2]);
121 beforec = 3;
122 break;
123 case FILESYS_TABLE:
124 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
125 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
126 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
127 dosql(before);
128 name = malloc(0);
129 id = atoi(before[2]);
130 id_to_name(id, MACHINE_TABLE, &name);
131 strcpy(before[2], name);
132 id = atoi(before[7]);
133 id_to_name(id, USERS_TABLE, &name);
134 strcpy(before[7], name);
135 id = atoi(before[8]);
136 id_to_name(id, LIST_TABLE, &name);
137 strcpy(before[8], name);
138 free(name);
139 beforec = 11;
140 break;
141 case QUOTA_TABLE:
142 strcpy(before[0], "?");
143 strcpy(before[1], argv[1]);
144 strcpy(before[2], "?");
145 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
146 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
147 dosql(&(before[3]));
148 strcpy(before[2], argv[1]);
149 beforec = 5;
150 break;
151 case LIST_TABLE:
152 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
153 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
154 "l.description FROM list l WHERE %s", qual);
155 dosql(before);
156 beforec = 10;
157 break;
158 case IMEMBERS_TABLE:
159 id = (int) argv[0];
160 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
161 "grouplist, gid FROM list WHERE list_id = %d", id);
162 dosql(&(before[3]));
163 name = malloc(0);
164 id_to_name(id, LIST_TABLE, &name);
165 strcpy(before[0], name);
166 strcpy(before[1], argv[1]);
167 id = (int) argv[2];
168 beforec = 9;
169 if (!strcmp(before[1], "USER"))
170 {
171 id_to_name(id, USERS_TABLE, &name);
172 EXEC SQL SELECT status INTO :before[9] FROM users
173 WHERE users_id = :id;
174 beforec = 10;
175 }
176 else if (!strcmp(before[1], "LIST"))
03c05291 177 id_to_name(id, LIST_TABLE, &name);
5eaef520 178 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
179 id_to_name(id, STRINGS_TABLE, &name);
180 strcpy(before[2], name);
181 free(name);
182 break;
183 default:
03c05291 184 /*
185 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
186 table_name[table]);
187 */
5eaef520 188 break;
189 }
a313cad2 190}
32cfe906 191
192
03c05291 193void incremental_clear_before(void)
32cfe906 194{
5eaef520 195 beforec = 0;
32cfe906 196}
197
32cfe906 198
03c05291 199/* add an element to the incremental queue for the changed row */
32cfe906 200
5eaef520 201void incremental_after(enum tables table, char *qual, char **argv)
a313cad2 202{
5eaef520 203 char *name;
204 EXEC SQL BEGIN DECLARE SECTION;
205 int id;
206 EXEC SQL END DECLARE SECTION;
207 struct iupdate *iu;
208
209 switch (table)
210 {
211 case USERS_TABLE:
212 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
213 "u.first, u.middle, u.status, u.clearid, u.type "
214 "FROM users u WHERE %s", qual);
215 dosql(after);
216 afterc = 9;
217 break;
218 case MACHINE_TABLE:
219 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
220 "WHERE %s", qual);
221 dosql(after);
222 afterc = 2;
223 break;
e688520a 224 case CLUSTERS_TABLE:
5eaef520 225 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
226 "FROM clusters c WHERE %s", qual);
227 dosql(after);
228 afterc = 3;
229 break;
230 case MCMAP_TABLE:
231 strcpy(after[0], argv[0]);
232 strcpy(after[1], argv[1]);
233 afterc = 2;
234 break;
235 case SVC_TABLE:
236 strcpy(after[0], argv[0]);
237 strcpy(after[1], argv[1]);
238 strcpy(after[2], argv[2]);
239 afterc = 3;
240 break;
241 case FILESYS_TABLE:
242 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
243 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
244 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
245 dosql(after);
246 name = malloc(0);
247 id = atoi(after[2]);
248 id_to_name(id, MACHINE_TABLE, &name);
249 strcpy(after[2], name);
250 id = atoi(after[7]);
251 id_to_name(id, USERS_TABLE, &name);
252 strcpy(after[7], name);
253 id = atoi(after[8]);
254 id_to_name(id, LIST_TABLE, &name);
255 strcpy(after[8], name);
256 free(name);
257 afterc = 11;
258 break;
259 case QUOTA_TABLE:
260 strcpy(after[0], "?");
261 strcpy(after[1], argv[1]);
262 strcpy(after[2], "?");
263 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
264 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
265 qual, argv[1]);
266 dosql(&(after[3]));
267 afterc = 5;
268 break;
269 case LIST_TABLE:
270 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
271 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
272 "l.description FROM list l WHERE %s", qual);
273 dosql(after);
274 afterc = 10;
275 break;
276 case IMEMBERS_TABLE:
277 id = (int) argv[0];
278 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
279 "grouplist, gid FROM list WHERE list_id = %d", id);
280 dosql(&(after[3]));
281 name = malloc(0);
282 id_to_name(id, LIST_TABLE, &name);
283 strcpy(after[0], name);
284 strcpy(after[1], argv[1]);
285 id = (int) argv[2];
286 afterc = 9;
287 if (!strcmp(after[1], "USER"))
288 {
289 id_to_name(id, USERS_TABLE, &name);
290 EXEC SQL SELECT status INTO :after[9] FROM users
291 WHERE users_id = :id;
292 afterc = 10;
32cfe906 293 }
5eaef520 294 else if (!strcmp(after[1], "LIST"))
295 id_to_name(id, LIST_TABLE, &name);
296 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
297 id_to_name(id, STRINGS_TABLE, &name);
298 strcpy(after[2], name);
299 free(name);
300 break;
301 case NO_TABLE:
302 afterc = 0;
303 table = beforetable;
304 break;
305 default:
03c05291 306 /*
307 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
308 table_name[table]);
309 */
5eaef520 310 break;
32cfe906 311 }
5eaef520 312
e688520a 313 iu = xmalloc(sizeof(struct iupdate));
5eaef520 314 iu->table = table_name[table];
315 iu->beforec = beforec;
e688520a 316 iu->before = mr_copy_args(before, beforec);
5eaef520 317 iu->afterc = afterc;
e688520a 318 iu->after = mr_copy_args(after, afterc);
5eaef520 319 sq_save_data(incremental_sq, iu);
a313cad2 320}
32cfe906 321
03c05291 322void incremental_clear_after(void)
323{
5eaef520 324 incremental_after(NO_TABLE, NULL, NULL);
03c05291 325}
326
32cfe906 327
328/* Called when the current transaction is committed to start any queued
329 * incremental updates. This caches the update table the first time it
330 * is called.
331 */
332
333struct inc_cache {
5eaef520 334 struct inc_cache *next;
335 char *table, *service;
32cfe906 336};
337
338
03c05291 339void incremental_update(void)
32cfe906 340{
5eaef520 341 static int inited = 0;
342 static struct inc_cache *cache;
343 struct inc_cache *c;
344 EXEC SQL BEGIN DECLARE SECTION;
e688520a 345 char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
5eaef520 346 EXEC SQL END DECLARE SECTION;
347 struct iupdate *iu;
348
349 if (!inited)
350 {
351 inited++;
352
353 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
354 FROM incremental;
355 EXEC SQL OPEN inc;
356 while (1)
357 {
358 EXEC SQL FETCH inc INTO :tab, :serv;
359 if (sqlca.sqlcode)
360 break;
e688520a 361 c = xmalloc(sizeof(struct inc_cache));
5eaef520 362 c->next = cache;
e688520a 363 c->table = xstrdup(strtrim(tab));
364 c->service = xstrdup(strtrim(serv));
5eaef520 365 cache = c;
32cfe906 366 }
5eaef520 367 EXEC SQL CLOSE inc;
368 EXEC SQL COMMIT WORK;
32cfe906 369 }
370
5eaef520 371 while (sq_remove_data(incremental_sq, &iu))
372 {
373 for (c = cache; c; c = c->next)
374 {
375 if (!strcmp(c->table, iu->table))
376 {
377 iu->service = c->service;
378 sq_save_data(incremental_exec, iu);
e688520a 379 break;
32cfe906 380 }
381 }
e688520a 382 if (!c)
383 {
384 free_argv(iu->before, iu->beforec);
385 free_argv(iu->after, iu->afterc);
386 free(iu);
387 }
32cfe906 388 }
5eaef520 389 if (inc_running == 0)
390 next_incremental();
32cfe906 391}
392
393
03c05291 394void next_incremental(void)
32cfe906 395{
5eaef520 396 struct iupdate *iu;
e688520a 397 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
5eaef520 398 int i;
399 sigset_t sigs;
400
401 if (!incremental_exec)
402 incremental_init();
403
404 if (sq_empty(incremental_exec) ||
405 (inc_running && now - inc_started < INC_TIMEOUT))
406 return;
407
408 if (inc_running)
409 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
410
411 sq_remove_data(incremental_exec, &iu);
412 argv[1] = iu->table;
413 sprintf(cbefore, "%d", iu->beforec);
414 argv[2] = cbefore;
415 sprintf(cafter, "%d", iu->afterc);
416 argv[3] = cafter;
417 for (i = 0; i < iu->beforec; i++)
418 argv[4 + i] = iu->before[i];
419 for (i = 0; i < iu->afterc; i++)
420 argv[4 + iu->beforec + i] = iu->after[i];
421
422 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
423 argv[0] = prog;
424 argv[4 + iu->beforec + iu->afterc] = 0;
425
426 sigemptyset(&sigs);
427 sigaddset(&sigs, SIGCHLD);
428 sigprocmask(SIG_BLOCK, &sigs, NULL);
429 inc_pid = vfork();
430 switch (inc_pid)
431 {
32cfe906 432 case 0:
5eaef520 433 execv(prog, argv);
434 _exit(1);
32cfe906 435 case -1:
5eaef520 436 com_err(whoami, 0, "Failed to start incremental update");
437 break;
32cfe906 438 default:
5eaef520 439 inc_running = 1;
440 inc_started = now;
32cfe906 441 }
5eaef520 442 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
32cfe906 443
5eaef520 444 free_argv(iu->before, iu->beforec);
445 free_argv(iu->after, iu->afterc);
446 free(iu);
32cfe906 447}
448
449
450/* Called when the current transaction is aborted to throw away any queued
451 * incremental updates
452 */
453
03c05291 454void incremental_flush(void)
32cfe906 455{
5eaef520 456 struct iupdate *iu;
32cfe906 457
5eaef520 458 while (sq_get_data(incremental_sq, &iu))
459 {
460 free_argv(iu->before, iu->beforec);
461 free_argv(iu->after, iu->afterc);
462 free(iu);
32cfe906 463 }
5eaef520 464 sq_destroy(incremental_sq);
465 incremental_sq = sq_create();
32cfe906 466}
467
468
5eaef520 469void free_argv(char **argv, int argc)
32cfe906 470{
5eaef520 471 while (--argc >= 0)
472 free(argv[argc]);
473 free(argv);
32cfe906 474}
03c05291 475
476int table_num(char *name)
477{
478 int i;
479
5eaef520 480 for (i = num_tables - 1; i; i--)
481 {
482 if (!strcmp(table_name[i], name))
483 break;
484 }
03c05291 485
486 return i; /* 0 = "none" if no match */
487}
This page took 0.136057 seconds and 5 git commands to generate.