1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * Sleepycat Software. All rights reserved. 6 */ 7 #include "config.h" 8 9 #ifndef lint 10 static const char sccsid[] = "@(#)log_register.c 10.22 (Sleepycat) 9/27/98"; 11 #endif /* not lint */ 12 13 #ifndef NO_SYSTEM_INCLUDES 14 #include <sys/types.h> 15 16 #include <errno.h> 17 #include <string.h> 18 #endif 19 20 #include "db_int.h" 21 #include "shqueue.h" 22 #include "log.h" 23 #include "common_ext.h" 24 25 /* 26 * log_register -- 27 * Register a file name. 28 */ 29 int 30 log_register(dblp, dbp, name, type, idp) 31 DB_LOG *dblp; 32 DB *dbp; 33 const char *name; 34 DBTYPE type; 35 u_int32_t *idp; 36 { 37 DBT fid_dbt, r_name; 38 DB_LSN r_unused; 39 FNAME *fnp, *reuse_fnp; 40 size_t len; 41 u_int32_t maxid; 42 int inserted, ret; 43 char *fullname; 44 void *namep; 45 46 inserted = 0; 47 fullname = NULL; 48 fnp = namep = reuse_fnp = NULL; 49 50 LOG_PANIC_CHECK(dblp); 51 52 /* Check the arguments. */ 53 if (type != DB_BTREE && type != DB_HASH && type != DB_RECNO) { 54 __db_err(dblp->dbenv, "log_register: unknown DB file type"); 55 return (EINVAL); 56 } 57 58 /* Get the log file id. */ 59 if ((ret = __db_appname(dblp->dbenv, 60 DB_APP_DATA, NULL, name, 0, NULL, &fullname)) != 0) 61 return (ret); 62 63 LOCK_LOGREGION(dblp); 64 65 /* 66 * See if we've already got this file in the log, finding the 67 * (maximum+1) in-use file id and some available file id (if we 68 * find an available fid, we'll use it, else we'll have to allocate 69 * one after the maximum that we found). 70 */ 71 for (maxid = 0, fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname); 72 fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { 73 if (fnp->ref == 0) { /* Entry is not in use. */ 74 if (reuse_fnp == NULL) 75 reuse_fnp = fnp; 76 continue; 77 } 78 if (!memcmp(dbp->fileid, fnp->ufid, DB_FILE_ID_LEN)) { 79 ++fnp->ref; 80 goto found; 81 } 82 if (maxid <= fnp->id) 83 maxid = fnp->id + 1; 84 } 85 86 /* Fill in fnp structure. */ 87 88 if (reuse_fnp != NULL) /* Reuse existing one. */ 89 fnp = reuse_fnp; 90 else if ((ret = __db_shalloc(dblp->addr, sizeof(FNAME), 0, &fnp)) != 0) 91 goto err; 92 else /* Allocate a new one. */ 93 fnp->id = maxid; 94 95 fnp->ref = 1; 96 fnp->s_type = type; 97 memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN); 98 99 len = strlen(name) + 1; 100 if ((ret = __db_shalloc(dblp->addr, len, 0, &namep)) != 0) 101 goto err; 102 fnp->name_off = R_OFFSET(dblp, namep); 103 memcpy(namep, name, len); 104 105 /* Only do the insert if we allocated a new fnp. */ 106 if (reuse_fnp == NULL) 107 SH_TAILQ_INSERT_HEAD(&dblp->lp->fq, fnp, q, __fname); 108 inserted = 1; 109 110 found: /* Log the registry. */ 111 if (!F_ISSET(dblp, DBC_RECOVER)) { 112 r_name.data = (void *)name; /* XXX: Yuck! */ 113 r_name.size = strlen(name) + 1; 114 memset(&fid_dbt, 0, sizeof(fid_dbt)); 115 fid_dbt.data = dbp->fileid; 116 fid_dbt.size = DB_FILE_ID_LEN; 117 if ((ret = __log_register_log(dblp, NULL, &r_unused, 118 0, LOG_OPEN, &r_name, &fid_dbt, fnp->id, type)) != 0) 119 goto err; 120 if ((ret = __log_add_logid(dblp, dbp, name, fnp->id)) != 0) 121 goto err; 122 } 123 124 if (0) { 125 err: /* 126 * XXX 127 * We should grow the region. 128 */ 129 if (inserted) 130 SH_TAILQ_REMOVE(&dblp->lp->fq, fnp, q, __fname); 131 if (namep != NULL) 132 __db_shalloc_free(dblp->addr, namep); 133 if (fnp != NULL) 134 __db_shalloc_free(dblp->addr, fnp); 135 } 136 137 if (idp != NULL) 138 *idp = fnp->id; 139 UNLOCK_LOGREGION(dblp); 140 141 if (fullname != NULL) 142 __os_freestr(fullname); 143 144 return (ret); 145 } 146 147 /* 148 * log_unregister -- 149 * Discard a registered file name. 150 */ 151 int 152 log_unregister(dblp, fid) 153 DB_LOG *dblp; 154 u_int32_t fid; 155 { 156 DBT fid_dbt, r_name; 157 DB_LSN r_unused; 158 FNAME *fnp; 159 int ret; 160 161 LOG_PANIC_CHECK(dblp); 162 163 ret = 0; 164 LOCK_LOGREGION(dblp); 165 166 /* Find the entry in the log. */ 167 for (fnp = SH_TAILQ_FIRST(&dblp->lp->fq, __fname); 168 fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) 169 if (fid == fnp->id) 170 break; 171 if (fnp == NULL) { 172 __db_err(dblp->dbenv, "log_unregister: non-existent file id"); 173 ret = EINVAL; 174 goto ret1; 175 } 176 177 /* Unlog the registry. */ 178 if (!F_ISSET(dblp, DBC_RECOVER)) { 179 memset(&r_name, 0, sizeof(r_name)); 180 r_name.data = R_ADDR(dblp, fnp->name_off); 181 r_name.size = strlen(r_name.data) + 1; 182 memset(&fid_dbt, 0, sizeof(fid_dbt)); 183 fid_dbt.data = fnp->ufid; 184 fid_dbt.size = DB_FILE_ID_LEN; 185 if ((ret = __log_register_log(dblp, NULL, &r_unused, 186 0, LOG_CLOSE, &r_name, &fid_dbt, fid, fnp->s_type)) != 0) 187 goto ret1; 188 } 189 190 /* 191 * If more than 1 reference, just decrement the reference and return. 192 * Otherwise, free the name. 193 */ 194 --fnp->ref; 195 if (fnp->ref == 0) 196 __db_shalloc_free(dblp->addr, R_ADDR(dblp, fnp->name_off)); 197 198 /* 199 * Remove from the process local table. If this operation is taking 200 * place during recovery, then the logid was never added to the table, 201 * so do not remove it. 202 */ 203 if (!F_ISSET(dblp, DBC_RECOVER)) 204 __log_rem_logid(dblp, fid); 205 206 ret1: UNLOCK_LOGREGION(dblp); 207 return (ret); 208 } 209