Annotation of freem/src/journal.c, revision 1.1

1.1     ! snw         1: /*
        !             2:  *                            *
        !             3:  *                           * *
        !             4:  *                          *   *
        !             5:  *                     ***************
        !             6:  *                      * *       * *
        !             7:  *                       *  MUMPS  *
        !             8:  *                      * *       * *
        !             9:  *                     ***************
        !            10:  *                          *   *
        !            11:  *                           * *
        !            12:  *                            *
        !            13:  *
        !            14:  *   journal.c
        !            15:  *    Implementation of FreeM journaling
        !            16:  *
        !            17:  *  
        !            18:  *   Author: Serena Willis <jpw@coherent-logic.com>
        !            19:  *    Copyright (C) 1998 MUG Deutschland
        !            20:  *    Copyright (C) 2020 Coherent Logic Development LLC
        !            21:  *
        !            22:  *
        !            23:  *   This file is part of FreeM.
        !            24:  *
        !            25:  *   FreeM is free software: you can redistribute it and/or modify
        !            26:  *   it under the terms of the GNU Affero Public License as published by
        !            27:  *   the Free Software Foundation, either version 3 of the License, or
        !            28:  *   (at your option) any later version.
        !            29:  *
        !            30:  *   FreeM is distributed in the hope that it will be useful,
        !            31:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            32:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            33:  *   GNU Affero Public License for more details.
        !            34:  *
        !            35:  *   You should have received a copy of the GNU Affero Public License
        !            36:  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
        !            37:  *
        !            38:  **/
        !            39: 
        !            40: #include <stdio.h>
        !            41: #include <string.h>
        !            42: #include <stdlib.h>
        !            43: 
        !            44: #include <sys/types.h>
        !            45: #include <sys/stat.h>
        !            46: #include <fcntl.h>
        !            47: #include <time.h>
        !            48: 
        !            49: #include <unistd.h>
        !            50: #include <errno.h>
        !            51: 
        !            52: #include "mpsdef.h"
        !            53: #include "journal.h"
        !            54: #include "transact.h"
        !            55: #include "iniconf.h"
        !            56: #include "shmmgr.h"
        !            57: 
        !            58: unsigned long jnl_tran_id;       /* transaction id for journaling */
        !            59: unsigned long jnl_cut_threshold; /* byte limit of journal file before cutting new */
        !            60: char jnl_file_path[PATH_MAX];    /* path to journal file */
        !            61: char jnl_host_id[256];           /* host ID (configured at install time) */
        !            62: short jnl_locked = FALSE;        /* is the journal locked? */
        !            63: int jnl_desc = 0;                /* journal file descriptor */
        !            64: 
        !            65: short jnl_enabled = FALSE;
        !            66: 
        !            67: void jnl_cut(void);
        !            68: void jnl_panic(char *msg);
        !            69: void jnl_update_tid(void);
        !            70: void jnl_lock(void);
        !            71: void jnl_unlock(void);
        !            72: 
        !            73: short jnl_init(char *jnlfile, char *hostid, unsigned long cut_threshold, unsigned long tran_id)
        !            74: {
        !            75: 
        !            76:     jnl_hdr_t hdr;
        !            77:     char tmsg[256];
        !            78:     
        !            79:     char m[5] = "FRMJL";
        !            80: 
        !            81:     strncpy (jnl_host_id, hostid, 255);
        !            82:     jnl_cut_threshold = cut_threshold;
        !            83: 
        !            84:     /* cannot re-init in a running process */
        !            85:     if ((jnl_desc) && (tran_id == 0)) return FALSE;
        !            86: 
        !            87:     strncpy (jnl_file_path, jnlfile, PATH_MAX - 1);
        !            88:     
        !            89:     if (!file_exists (jnl_file_path)) {
        !            90: 
        !            91:         /* this is a new journal file */
        !            92:         jnl_tran_id = tran_id;
        !            93: 
        !            94:         jnl_desc = open (jnl_file_path, O_CREAT | O_APPEND | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
        !            95: 
        !            96:         if (jnl_desc == -1) jnl_panic ("error creating new journal file");
        !            97:         
        !            98:         jnl_lock ();
        !            99: 
        !           100:         memcpy (hdr.magic, m, 5);
        !           101:         hdr.fmt_version = FRM_JNL_VERSION;
        !           102:         snprintf (hdr.host_triplet, 40, "%s", HOST);
        !           103:         
        !           104:         if (write (jnl_desc, &hdr, sizeof (jnl_hdr_t)) == -1) {
        !           105:             snprintf (tmsg, 255, "error %d writing to journal file", errno);
        !           106:             jnl_panic (tmsg);
        !           107:         }
        !           108: 
        !           109:         jnl_unlock ();
        !           110: 
        !           111:         close (jnl_desc);
        !           112: 
        !           113:     }
        !           114:     else {
        !           115: 
        !           116:         /* this journal file already exists */
        !           117: 
        !           118:         jnl_desc = open (jnl_file_path, O_APPEND | O_RDWR);
        !           119: 
        !           120:         lseek (jnl_desc, 0L, SEEK_SET);
        !           121:         
        !           122:         jnl_lock ();
        !           123: 
        !           124:         read (jnl_desc, &hdr, sizeof (jnl_hdr_t));
        !           125: 
        !           126:         if (strncmp (hdr.magic, m, 5) != 0) {
        !           127:             
        !           128:             set_io (UNIX);
        !           129:             fprintf (stderr, "%s is not a valid FreeM journal file.\n", jnl_file_path);
        !           130:             set_io (MUMPS);
        !           131: 
        !           132:             return FALSE;
        !           133: 
        !           134:         }
        !           135: 
        !           136:         if (hdr.fmt_version != FRM_JNL_VERSION) {
        !           137:             
        !           138:             set_io (UNIX);
        !           139:             fprintf (stderr, "Journal file version mismatch.\n");
        !           140:             set_io (MUMPS);
        !           141: 
        !           142:             return FALSE;
        !           143: 
        !           144:         }
        !           145: 
        !           146:         //strncpy (jnl_host_id, hdr.)
        !           147:         
        !           148:         jnl_unlock ();
        !           149: 
        !           150:         close (jnl_desc);
        !           151: 
        !           152:     }
        !           153: 
        !           154:     jnl_desc = open (jnl_file_path, O_APPEND | O_RDWR);
        !           155: 
        !           156:     lseek (jnl_desc, 0L, SEEK_END);
        !           157: 
        !           158:     jnl_lock ();
        !           159:     jnl_update_tid ();
        !           160:     jnl_unlock ();
        !           161: 
        !           162:     jnl_enabled = TRUE;
        !           163: 
        !           164:     return TRUE;
        !           165: 
        !           166: }
        !           167: 
        !           168: void jnl_cleanup(void)
        !           169: {
        !           170: 
        !           171:     if (jnl_desc) {
        !           172:         jnl_unlock ();
        !           173:         close (jnl_desc);
        !           174:     }
        !           175: 
        !           176:     return;
        !           177: 
        !           178: }
        !           179: 
        !           180: short jnl_ent_write(short action, char *key, char *data)
        !           181: {
        !           182: 
        !           183:     jnl_ent_t ent;
        !           184:     size_t siz;
        !           185:     char msg[256];
        !           186: 
        !           187:     jnl_lock ();
        !           188: 
        !           189:     if ((tp_level == 0) && (action != JNLA_TSTART)) {
        !           190:         /* make sure we have the latest transaction ID */
        !           191:         jnl_update_tid ();
        !           192:     }
        !           193: 
        !           194:     siz = lseek (jnl_desc, 0L, SEEK_END);
        !           195: 
        !           196:     if ((siz + sizeof (jnl_ent_t)) >= jnl_cut_threshold) jnl_cut ();
        !           197: 
        !           198:     /* only increment the transaction ID if we're NOT in a transaction
        !           199:        or this action begins one. */
        !           200:     if ((tp_level == 0) || action == JNLA_TSTART) {
        !           201:         if (tp_get_sem () == FALSE) {
        !           202:             jnl_panic ("could not get transaction processing semaphore");
        !           203:         }
        !           204:         else {
        !           205:             jnl_tran_id++;
        !           206:             shm_config->hdr->tp_serial_number = jnl_tran_id;
        !           207: 
        !           208:             tp_release_sem ();
        !           209:         }
        !           210:     }
        !           211: 
        !           212:     ent.tran_id = jnl_tran_id;
        !           213:     ent.ts = time (NULL);
        !           214:     ent.pid = (pid_t) pid;
        !           215:     ent.action = action;
        !           216: 
        !           217:     strncpy (ent.host_id, jnl_host_id, 255);
        !           218:     strncpy (ent.key, key, 1023);
        !           219:     strncpy (ent.data, data, 1023);
        !           220: 
        !           221:     lseek (jnl_desc, 0L, SEEK_END);
        !           222: 
        !           223:     errno = 0;
        !           224:     if ((siz = write (jnl_desc, &ent, sizeof (jnl_ent_t))) < sizeof (jnl_ent_t)) {
        !           225: 
        !           226:         switch (errno) {
        !           227: 
        !           228:             case ENOSPC:
        !           229:                 snprintf (msg, 255, "ran out of disk space while attempting journal write");
        !           230:                 break;
        !           231: 
        !           232:             default:
        !           233:                 snprintf (msg, 255, strerror (errno));
        !           234:                 break;
        !           235: 
        !           236:         }
        !           237: 
        !           238:         jnl_panic (msg);
        !           239:                 
        !           240:     }
        !           241: 
        !           242:     jnl_unlock ();
        !           243: 
        !           244:     return 1;
        !           245:     
        !           246: }
        !           247: 
        !           248: void jnl_update_tid(void)
        !           249: {
        !           250:     jnl_ent_t ent;
        !           251: 
        !           252:     if  (tp_get_sem () == TRUE) {
        !           253:     
        !           254:         if (first_process == TRUE) {
        !           255:     
        !           256:             if (!jnl_desc) return;
        !           257:             
        !           258:             lseek (jnl_desc, 0L, SEEK_END);
        !           259:             lseek (jnl_desc, -sizeof (jnl_ent_t), SEEK_CUR);
        !           260: 
        !           261:             read (jnl_desc, &ent, sizeof (jnl_ent_t));
        !           262:             
        !           263:             jnl_tran_id = ent.tran_id;
        !           264: 
        !           265:             shm_config->hdr->tp_serial_number = ent.tran_id;
        !           266: 
        !           267:         }
        !           268:         else {
        !           269:             jnl_tran_id = shm_config->hdr->tp_serial_number;
        !           270:         }
        !           271: 
        !           272:         tp_release_sem ();
        !           273: 
        !           274:     }
        !           275:     else {
        !           276:         jnl_panic ("jnl_update_tid:  could not acquire transaction processing sempahore");
        !           277:     }
        !           278: 
        !           279: }
        !           280: 
        !           281: inline void jnl_lock(void) 
        !           282: {
        !           283:     struct flock lock;
        !           284: 
        !           285:     lock.l_type = F_WRLCK;
        !           286:     lock.l_whence = SEEK_SET;
        !           287:     lock.l_start = 0;
        !           288:     lock.l_len = 0;
        !           289: 
        !           290:     fcntl (jnl_desc, F_SETLK, &lock);
        !           291: 
        !           292:     jnl_locked = TRUE;
        !           293: 
        !           294:     return;
        !           295: }
        !           296: 
        !           297: inline void jnl_unlock(void)
        !           298: {
        !           299:     struct flock lock;
        !           300: 
        !           301:     lock.l_type = F_UNLCK;
        !           302:     lock.l_whence = SEEK_SET;
        !           303:     lock.l_start = 0;
        !           304:     lock.l_len = 0;
        !           305: 
        !           306:     fcntl (jnl_desc, F_SETLK, &lock);
        !           307: 
        !           308:     jnl_locked = FALSE;
        !           309: 
        !           310:     return;
        !           311: }
        !           312: 
        !           313: void jnl_cut(void)
        !           314: {
        !           315:     char cutname[PATH_MAX];
        !           316: 
        !           317: 
        !           318:     if (jnl_desc) {
        !           319: 
        !           320:         jnl_lock ();
        !           321: 
        !           322:         jnl_update_tid ();
        !           323: 
        !           324:         snprintf (cutname, PATH_MAX - 1, "%s.%ld", jnl_file_path, jnl_tran_id);
        !           325:         close (jnl_desc);
        !           326: 
        !           327:         rename (jnl_file_path, cutname);
        !           328: 
        !           329:         if(tp_level == 0) {
        !           330:             jnl_init (jnl_file_path, jnl_host_id, jnl_cut_threshold, ++jnl_tran_id);
        !           331:         }
        !           332:         else {
        !           333:             jnl_init (jnl_file_path, jnl_host_id, jnl_cut_threshold, jnl_tran_id);
        !           334:         }
        !           335: 
        !           336:         jnl_unlock();
        !           337: 
        !           338:     }
        !           339: 
        !           340:     return;
        !           341: 
        !           342: }
        !           343: 
        !           344: void jnl_panic(char *msg)
        !           345: {
        !           346:     set_io (UNIX);
        !           347: 
        !           348:     if (tp_level > 0) {
        !           349:         fprintf (stderr, "journal error:  [%s] (rolling back all transactions)\n", msg);
        !           350:         tp_trollback (tp_level);
        !           351:     }
        !           352:     else {
        !           353:         fprintf (stderr, "journal error:  [%s]\n", msg);
        !           354:     }
        !           355: 
        !           356:     jnl_cleanup ();
        !           357: 
        !           358:     exit (1);
        !           359: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>