source: trunk/third/moira/dbck/members.pc @ 24319

Revision 24319, 14.8 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: members.pc 3956 2010-01-05 20:56:56Z zacheiss $
2 *
3 */
4
5#include <stdio.h>
6#include <signal.h>
7#include <string.h>
8#include <moira.h>
9
10RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/dbck/members.pc $ $Id: members.pc 3956 2010-01-05 20:56:56Z zacheiss $");
11
12#define FIXERRORS
13
14#define max(x, y)       ((x) > (y) ? (x) : (y))
15
16EXEC SQL INCLUDE sqlca;
17
18struct member {
19    int list_id;
20    int member_id;
21    union {
22        short all;
23        struct {
24            short u_ref_count:12;
25            unsigned short u_direct:1;
26            unsigned short u_baddirect:1;
27            unsigned short u_found:1;
28            unsigned short u_scanned:1;
29        } u_flags;
30    } flags;
31} *find_member(), *allocmember();
32#define frefc           flags.u_flags.u_ref_count
33#define fdirect         flags.u_flags.u_direct
34#define fbaddirect      flags.u_flags.u_baddirect
35#define ffound          flags.u_flags.u_found
36#define fscanned        flags.u_flags.u_scanned
37#define fall            flags.all
38
39#define member2id(c, id)        (((c & 0xff) << 24) | (id & 0xffffff))
40#define id2type(id)             ((id >> 24) & 0xff)
41#define id2id(id)               (id & 0xffffff)
42
43struct member_list {
44    struct member_list *next;
45    struct member *member;
46};
47
48struct hash *lists, *members;
49void fix_member(), display_member();
50int debug = 0, records = 0;
51
52char *db = "moira/moira";
53
54main(argc, argv)
55int argc;
56char **argv;
57{
58    char buf[256];
59
60#ifdef DEBUG
61    if (argc > 1)
62      debug = atoi(argv[1]);
63#endif /* DEBUG */
64
65/*  ingres sms */
66    EXEC SQL CONNECT :db;
67/*  begin transaction */
68/*  range of m is imembers */
69    /* No equivalent */
70
71    lists = create_hash(50000);
72    members = create_hash(300000);
73    records = 0;
74
75    load_members();
76#ifdef DEBUG
77    if (debug > 3)
78      hash_step(lists, display_member, NULL);
79#endif /* DEBUG */
80    verify_members();
81    fix_members();
82
83#ifdef FIXERRORS
84    printf("Commit changes (Y/N)?");
85    fflush(stdout);
86    fgets(buf, sizeof(buf), stdin);
87    if (buf[0] == 'Y' || buf[0] == 'y') {
88        printf("Ending transaction\n");
89/*      end transaction */
90        EXEC SQL COMMIT WORK;
91    } else {
92#endif /* FIXERRORS */
93        printf("Aborting transaction\n");
94/*      abort */
95        EXEC SQL ROLLBACK WORK;
96#ifdef FIXERRORS
97    }
98#endif /* FIXERRORS */
99
100/*  exit */
101    /* No equivalent (?) */
102    printf("Done.\n");
103
104    exit(0);
105}
106
107
108load_members()
109{
110    struct member *m, *m1, *md, *ma;
111    struct member_list *descendants, *ancestors, *desc, *ance, la, ld;
112    EXEC SQL BEGIN DECLARE SECTION;
113    int list_id, member_id, ref_count, ref;
114    char mtype[9];
115    EXEC SQL END DECLARE SECTION;
116    struct save_queue *sq;
117
118    printf("Loading members\n");
119    sq = sq_create();
120
121/*  retrieve (list_id = m.#list_id, member_id = m.#member_id,
122 *            mtype = m.#member_type, ref_count = m.#ref_count)
123 *      where m.direct = 1 {  */
124    EXEC SQL DECLARE csrm1 CURSOR FOR
125        SELECT list_id, member_id, member_type, ref_count FROM imembers
126            WHERE direct=1;
127    EXEC SQL OPEN csrm1;
128    while(1) {
129        EXEC SQL FETCH csrm1 INTO :list_id, :member_id, :mtype, :ref_count;
130        if(sqlca.sqlcode != 0) break;
131
132#ifdef DEBUG
133      if (debug > 5)
134        printf("Working on list %d member %s %d refc %d\n",
135               list_id, mtype, member_id, ref_count);
136#endif /* DEBUG */
137      if ((m = find_member(list_id, member2id(mtype[0], member_id))) == NULL) {
138          m = allocmember();
139          m->list_id = list_id;
140          m->member_id = member2id(mtype[0], member_id);
141          insert_list(m);
142          insert_member(m);
143      }
144      m->fdirect = 1;
145      la.next = (struct member_list *) hash_lookup(members,
146                                                   member2id('L', list_id));
147      la.member = m;
148      if (isinchain(m, la.next))
149        ance = la.next;
150      else
151        ance = &la;
152      if (mtype[0] == 'L')
153        ld.next = (struct member_list *) hash_lookup(lists, member_id);
154      else
155        ld.next = NULL;
156      ld.member = m;
157      if (isinchain(m, ld.next))
158        desc = ld.next;
159      else
160        desc = &ld;
161#ifdef DEBUG
162      if (debug > 5)
163        printf("%d ancestors, %d descendants\n",
164               chainlen(ance), chainlen(desc));
165#endif /* DEBUG */
166      for (ancestors = ance; ancestors; ancestors = ancestors->next) {
167          ma = ancestors->member;
168          for (descendants = desc; descendants; descendants=descendants->next) {
169              md = descendants->member;
170              if (member2id('L', ma->list_id) == md->member_id)
171                fprintf(stderr, "Loop detected! list %d member %d\n",
172                        md->list_id, ma->member_id);
173              ref = md->frefc * ma->frefc;
174              if (ref == 0) {
175                  ref = max(md->frefc, ma->frefc);
176                  if (ref == 0)
177                    ref = 1;
178              }
179#ifdef DEBUG
180              if (debug > 5)
181                printf("Checking list %d member %d, ref = %d\n",
182                       ma->list_id, id2id(md->member_id), ref);
183#endif /* DEBUG */
184              if (m1 = find_member(ma->list_id, md->member_id)) {
185                  m1->frefc += ref;
186#ifdef DEBUG
187                  if (debug > 5)
188                    printf("set refc to %d (%d) on list %d, member %d\n",
189                           m1->frefc, ref, m1->list_id, id2id(m1->member_id));
190#endif /* DEBUG */
191                  if (ma == m && md == m)
192                    m1->fdirect = 1;
193              } else {
194                  m1 = allocmember();
195                  m1->list_id = ma->list_id;
196                  m1->member_id = md->member_id;
197                  m1->frefc = ref;
198#ifdef DEBUG
199                  if (debug > 5)
200                    printf("set new refc to %d (%d) on list %d, member %d\n",
201                           m1->frefc, ref, m1->list_id, id2id(m1->member_id));
202#endif /* DEBUG */
203                  sq_save_data(sq, m1);
204              }
205          }
206      }
207      while (sq_get_data(sq, &m)) {
208          insert_list(m);
209          insert_member(m);
210      }
211      sq_destroy(sq);
212      sq = sq_create();
213    }
214    EXEC SQL CLOSE csrm1;
215    printf("created %d records\n", records);
216}
217
218verify_members()
219{
220    struct member *m;
221    struct save_queue *sq;
222    EXEC SQL BEGIN DECLARE SECTION;
223    int list_id, member_id, ref_count, dflag;
224    char mtype[9];
225    EXEC SQL END DECLARE SECTION;
226    int errxtra, errbref, errbdir;
227#ifdef DEBUG
228    int ref0, ref1, ref2, ref3, refg;
229    int db0, db1, db2, db3, dbg;
230#endif /* DEBUG */
231
232    /* verify members from database */
233    printf("Verifying members\n");
234    errxtra = errbref = errbdir = 0;
235#ifdef DEBUG
236    ref0 = ref1 = ref2 = ref3 = refg = 0;
237    db0 = db1 = db2 = db3 = dbg = 0;
238#endif /* DEBUG */
239    sq = sq_create();
240/*  retrieve (list_id = m.#list_id, member_id = m.#member_id,
241 *            mtype = m.member_type, ref_count = m.#ref_count,
242 *            dflag = m.#direct) { */
243    EXEC SQL DECLARE csrm2 CURSOR FOR
244        SELECT list_id, member_id, member_type, ref_count, direct
245            FROM imembers;
246    EXEC SQL OPEN csrm2;
247    while(1) {
248        EXEC SQL FETCH csrm2
249            INTO :list_id, :member_id, :mtype, :ref_count, :dflag;
250        if(sqlca.sqlcode != 0) break;
251
252#ifdef DEBUG
253      if (debug > 1)
254        switch (ref_count) {
255        case 0: db0++; break;
256        case 1: db1++; break;
257        case 2: db2++; break;
258        case 3: db3++; break;
259        default: dbg++;
260        }
261#endif /* DEBUG */
262      m = find_member(list_id, member2id(mtype[0], member_id));
263      if (m == NULL) {
264          m = allocmember();
265          m->list_id = list_id;
266          m->member_id = member2id(mtype[0], member_id);
267          m->fdirect = dflag;
268          m->frefc = ref_count;
269          sq_save_data(sq, m);
270          errxtra++;
271      } else {
272          m->ffound = 1;
273#ifdef DEBUG   
274          if (debug > 1)
275            switch (m->frefc) {
276            case 0: ref0++; break;
277            case 1: ref1++; break;
278            case 2: ref2++; break;
279            case 3: ref3++; break;
280            default: refg++;
281            }
282#endif /* DEBUG */
283          m->frefc -= ref_count;
284          if (m->frefc != 0)
285            errbref++;
286          if (m->fdirect != dflag) {
287              m->fbaddirect = 1;
288              errbdir++;
289          }
290      }
291    }
292    EXEC SQL CLOSE csrm2;
293    printf("Found %d extra records, %d bad ref counts, %d bad direct flags\n",
294           errxtra, errbref, errbdir);
295#ifdef DEBUG
296    if (debug > 1) {
297        printf("Found in db: %d 0; %d 1; %d 2; %d 3; %d > 3\n",
298               db0, db1, db2, db3, dbg);
299        printf("Found  refs: %d 0; %d 1; %d 2; %d 3; %d > 3\n",
300               ref0, ref1, ref2, ref3, refg);
301    }
302#endif /* DEBUG */
303}
304
305
306fix_members()
307{
308    struct member *m;
309    struct save_queue *sq;
310    int errmis = 0;
311    EXEC SQL BEGIN DECLARE SECTION;
312    int list_id, member_id, rowcount;
313    char mtype[9];
314    EXEC SQL END DECLARE SECTION;
315    char buf[512];
316
317    /* fix any errors */
318    printf("Fixing errors\n");
319    hash_step(lists, fix_member, &errmis);
320    while (sq_get_data(sq, &m)) {
321        printf("Extraneous member record, deleting:\n");
322        list_id = m->list_id;
323        member_id = id2id(m->member_id);
324        switch (id2type(m->member_id)) {
325        case 'U': strcpy(mtype, "USER"); break;
326        case 'L': strcpy(mtype, "LIST"); break;
327        case 'S': strcpy(mtype, "STRING"); break;
328        case 'K': strcpy(mtype, "KERBEROS"); break;
329        default:
330            mtype[0] = id2type(m->member_id);
331            mtype[1] = 0;
332        }
333        printf("  List: %d, Member: %s %d, Refc: %d, Direct %d\n",
334               list_id, mtype, member_id, m->frefc, m->fdirect);
335#ifdef FIXERRORS
336/*      delete m where m.#list_id = list_id and m.#member_id = member_id
337 *              and m.member_type = mtype */
338        EXEC SQL DELETE FROM imembers WHERE list_id = :list_id AND
339            member_id = :member_id AND member_type = :mtype;
340        rowcount = sqlca.sqlerrd[2];
341        if (rowcount > 0)
342          printf("%d entr%s deleted\n", rowcount,
343                 rowcount == 1 ? "y" : "ies");
344#endif /* FIXERRORS */
345    }
346    if (errmis > 0)
347      printf("Added %d missing records\n", errmis);
348}
349
350
351insert_list(m)
352struct member *m;
353{
354    struct member_list *l, *l1;
355
356    l = (struct member_list *) hash_lookup(lists, m->list_id);
357    if (l == NULL) {
358        l = (struct member_list *)malloc(sizeof(struct member_list));
359        if (l == NULL) {
360            fprintf(stderr, "No memory for insert_list\n");
361            exit(1);
362        }
363        l->next = NULL;
364        l->member = m;
365        if( hash_store(lists, m->list_id, l) == -1 ) {
366          fprintf(stderr,"Out of mem while storing lists in hash table\n");
367          exit(1);
368        }
369        return;
370    }
371    for (l1 = l; l1; l1 = l1->next)
372      if (l1->member->member_id == m->member_id) {
373          fprintf(stderr, "Found 2nd copy of list record for\n");
374          fprintf(stderr, "List: %d, Member: %c %d, Refc: %d, Direct %d\n",
375                  m->list_id, id2type(m->member_id), id2id(m->member_id),
376                  m->frefc, m->fdirect);
377          kill(getpid(), SIGQUIT);
378          exit(2);
379      }
380
381    l1 = (struct member_list *)malloc(sizeof(struct member_list));
382    if (l1 == NULL) {
383        fprintf(stderr, "No memory for insert_list\n");
384        exit(1);
385    }
386    l1->next = l->next;
387    l->next = l1;
388    l1->member = m;
389}
390
391
392insert_member(m)
393struct member *m;
394{
395    struct member_list *l, *l1;
396
397    l = (struct member_list *) hash_lookup(members, m->member_id);
398    if (l == NULL) {
399        l = (struct member_list *)malloc(sizeof(struct member_list));
400        if (l == NULL) {
401            fprintf(stderr, "No memory for insert_member\n");
402            exit(1);
403        }
404        l->next = NULL;
405        l->member = m;
406        if( hash_store(members, m->member_id, l) == -1 ) {
407          fprintf(stderr,"Out of mem while storing members in hash table\n");
408          exit(1);
409        }
410        return;
411    }
412
413    for (l1 = l; l1; l1 = l1->next)
414      if (l1->member->list_id == m->list_id) {
415          fprintf(stderr, "Found 2nd copy of member record for\n");
416          fprintf(stderr, "List: %d, Member: %c %d, Refc: %d, Direct %d\n",
417                  m->list_id, id2type(m->member_id), id2id(m->member_id),
418                  m->frefc, m->fdirect);
419          kill(getpid(), SIGQUIT);
420          exit(2);
421      }
422
423    l1 = (struct member_list *)malloc(sizeof(struct member_list));
424    if (l1 == NULL) {
425        fprintf(stderr, "No memory for insert_member\n");
426        exit(1);
427    }
428    l1->next = l->next;
429    l->next = l1;
430    l1->member = m;
431}
432
433
434struct member *find_member(listid, memberid)
435int listid;
436int memberid;
437{
438    struct member_list *l;
439
440    for (l = (struct member_list *) hash_lookup(lists, listid); l; l = l->next)
441      if (l->member->member_id == memberid)
442        return(l->member);
443    return(NULL);
444}
445
446
447/*ARGSUSED*/
448void fix_member(dummy, l, errmis)
449int dummy;
450struct member_list *l;
451int *errmis;
452{
453    EXEC SQL BEGIN DECLARE SECTION;
454    int list_id, member_id, ref_count, dflag, rowcount;
455    char *mtype;
456    EXEC SQL END DECLARE SECTION;
457    char buf[2];
458    struct member *m;
459
460    for (; l; l = l->next) {
461        m = l->member;
462
463        if (m->fscanned)
464          continue;
465        m->fscanned = 1;
466        if (m->fbaddirect == 0 && m->frefc == 0 && m->ffound == 1)
467          continue;
468        if (m->ffound == 0) {
469            printf("Missing member record, adding:\n");
470            list_id = m->list_id;
471            member_id = id2id(m->member_id);
472            ref_count = m->frefc;
473            dflag = m->fdirect;
474            switch (id2type(m->member_id)) {
475            case 'U': mtype = "USER"; break;
476            case 'L': mtype = "LIST"; break;
477            case 'S': mtype = "STRING"; break;
478            case 'K': mtype = "KERBEROS"; break;
479            default:
480                mtype = buf;
481                buf[0] = id2type(m->member_id);
482                buf[1] = 0;
483            }
484            printf("  List: %d, Member: %s %d, Refc: %d, Direct %d\n",
485                   list_id, mtype, member_id, ref_count, dflag);
486            (*errmis)++;
487#ifdef FIXERRORS
488/*          append imembers (#list_id = list_id, #member_id = member_id,
489 *                           member_type = mtype, #ref_count = ref_count,
490 *                           direct = dflag); */
491            EXEC SQL INSERT INTO imembers (list_id, member_id,
492                member_type, ref_count, direct)
493              VALUES (:list_id, :member_id, :mtype, :ref_count, :dflag);
494            rowcount = sqlca.sqlerrd[2];
495            if (rowcount > 0)
496              printf("%d entr%s added\n", rowcount,
497                     rowcount == 1 ? "y" : "ies");
498#endif /* FIXERRORS */
499            continue;
500        }
501        printf("Member record has bad ref_count and/or direct flag, fixing\n");
502        list_id = m->list_id;
503        member_id = id2id(m->member_id);
504        ref_count = m->frefc;
505        dflag = m->fdirect;
506        switch (id2type(m->member_id)) {
507        case 'U': mtype = "USER"; break;
508        case 'L': mtype = "LIST"; break;
509        case 'S': mtype = "STRING"; break;
510        case 'K': mtype = "KERBEROS"; break;
511        default:
512            mtype = buf;
513            buf[0] = id2type(m->member_id);
514            buf[1] = 0;
515        }
516        printf("  List: %d, Member: %s %d, Refc: %d, Direct %d\n",
517               list_id, mtype, member_id, ref_count, dflag);
518#ifdef FIXERRORS
519/*      replace m (#ref_count = m.#ref_count + ref_count, direct = dflag)
520 *        where m.#list_id = list_id and m.#member_id = member_id and
521 *          m.member_type = mtype */
522        EXEC SQL UPDATE imembers
523            SET ref_count=ref_count+:ref_count, direct = :dflag
524            WHERE list_id = :list_id AND member_id = :member_id AND
525                member_tpe = :mtype;
526        rowcount = sqlca.sqlerrd[2];
527        if (rowcount > 0)
528          printf("%d entr%s updated\n", rowcount,
529                 rowcount == 1 ? "y" : "ies");
530#endif /* FIXERRORS */
531    }
532}
533
534
535struct member *allocmember()
536{
537    struct member *m;
538
539    m = (struct member *) malloc(sizeof(struct member));
540    if (m == NULL) {
541        fprintf(stderr, "No memory for new member\n");
542        exit(1);
543    }
544    m->fall = 0;
545    records++;
546    return(m);
547}
548
549
550int isinchain(m, l)
551struct member *m;
552struct member_list *l;
553{
554    for (; l; l = l->next)
555      if (l->member == m)
556        return(1);
557    return(0);
558}
559
560
561int chainlen(l)
562struct member_list *l;
563{
564    int i;
565    for (i = 0; l; l = l->next, i++);
566    return(i);
567}
568
569
570#ifdef DEBUG
571
572/*ARGSUSED*/
573void display_member(key, l, dummy1)
574int key, dummy1;
575struct member_list *l;
576{
577    struct member *m;
578    char *mtype;
579
580    printf("%d*", key);
581    for(; l; l = l->next) {
582        m = l->member;
583        switch (id2type(m->member_id)) {
584        case 'U': mtype = "USER"; break;
585        case 'L': mtype = "LIST"; break;
586        case 'S': mtype = "STRING"; break;
587        case 'K': mtype = "KERBEROS"; break;
588        default: mtype = "???"; break;
589        }
590        printf("List: %d, Member: %s %d, Refc: %d, Direct %d\n",
591               m->list_id, mtype, id2id(m->member_id), m->frefc,
592               m->fdirect);
593    }
594}
595
596#endif /* DEBUG */
Note: See TracBrowser for help on using the repository browser.