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>