📄 env_region.c
字号:
*/ if ((ret = __db_mutex_setup(dbenv, infop, &renv->mutex, MUTEX_NO_RECORD | MUTEX_NO_RLOCK)) != 0) { __db_err(dbenv, "%s: unable to initialize environment lock: %s", infop->name, db_strerror(ret)); goto err; } if (!F_ISSET(&renv->mutex, MUTEX_IGNORE) && (ret = __db_mutex_lock(dbenv, &renv->mutex)) != 0) { __db_err(dbenv, "%s: unable to acquire environment lock: %s", infop->name, db_strerror(ret)); goto err; } /* * Get the underlying REGION structure for this environment. Note, * we created the underlying OS region before we acquired the REGION * structure, which is backwards from the normal procedure. Update * the REGION structure. */ if ((ret = __db_des_get(dbenv, infop, infop, &rp)) != 0) {find_err: __db_err(dbenv, "%s: unable to find environment", infop->name); if (ret == 0) ret = EINVAL; goto err; } infop->rp = rp; rp->size = tregion.size; rp->segid = tregion.segid; /* * !!! * If we create an environment where regions are public and in system * memory, we have to inform processes joining the environment how to * attach to the shared memory segment. So, we write the shared memory * identifier into the file, to be read by those other processes. * * XXX * This is really OS-layer information, but I can't see any easy way * to move it down there without passing down information that it has * no right to know, e.g., that this is the one-and-only REGENV region * and not some other random region. */ if (tregion.segid != INVALID_REGION_SEGID) { ref.size = tregion.size; ref.segid = tregion.segid; if ((ret = __os_write( dbenv, dbenv->lockfhp, &ref, sizeof(ref), &nrw)) != 0) { __db_err(dbenv, "%s: unable to write out public environment ID: %s", infop->name, db_strerror(ret)); goto err; } } /* * If not doing thread locking, we need to save the file handle for * fcntl(2) locking. Otherwise, discard the handle, we no longer * need it, and the less contact between the buffer cache and the VM, * the better. */#if defined(HAVE_MUTEX_THREADS) if (F_ISSET(dbenv->lockfhp, DB_FH_VALID)) __os_closehandle(dbenv, dbenv->lockfhp);#endif /* Validate the file. */ renv->magic = DB_REGION_MAGIC; /* Discard our lock. */ MUTEX_UNLOCK(dbenv, &renv->mutex); /* Everything looks good, we're done. */ dbenv->reginfo = infop; return (0);err:retry: /* Close any open file handle. */ if (F_ISSET(dbenv->lockfhp, DB_FH_VALID)) (void)__os_closehandle(dbenv, dbenv->lockfhp); /* * If we joined or created the region, detach from it. If we created * it, destroy it. Note, there's a path in the above code where we're * using a temporary REGION structure because we haven't yet allocated * the real one. In that case the region address (addr) will be filled * in, but the REGION pointer (rp) won't. Fix it. */ if (infop->addr != NULL) { if (infop->rp == NULL) infop->rp = &tregion; /* Reset the addr value that we "corrected" above. */ infop->addr = infop->primary; (void)__os_r_detach(dbenv, infop, F_ISSET(infop, REGION_CREATE)); } /* Free the allocated name and/or REGINFO structure. */ if (infop->name != NULL) __os_free(dbenv, infop->name); __os_free(dbenv, infop); /* If we had a temporary error, wait awhile and try again. */ if (ret == 0) { if (++retry_cnt > 3) { __db_err(dbenv, "unable to join the environment"); ret = EAGAIN; } else { __os_sleep(dbenv, retry_cnt * 3, 0); goto loop; } } return (ret);}/* * __db_e_detach -- * Detach from the environment. * * PUBLIC: int __db_e_detach __P((DB_ENV *, int)); */int__db_e_detach(dbenv, destroy) DB_ENV *dbenv; int destroy;{ REGENV *renv; REGINFO *infop; infop = dbenv->reginfo; renv = infop->primary; if (F_ISSET(dbenv, DB_ENV_PRIVATE)) destroy = 1; /* Lock the environment. */ MUTEX_LOCK(dbenv, &renv->mutex); /* Decrement the reference count. */ if (renv->refcnt == 0) { __db_err(dbenv, "region %lu (environment): reference count went negative", infop->rp->id); } else --renv->refcnt; /* Release the lock. */ MUTEX_UNLOCK(dbenv, &renv->mutex); /* Close the locking file handle. */ if (F_ISSET(dbenv->lockfhp, DB_FH_VALID)) (void)__os_closehandle(dbenv, dbenv->lockfhp); /* Reset the addr value that we "corrected" above. */ infop->addr = infop->primary; /* * If we are destroying the environment, we need to * destroy any system resources backing the mutex, as well * as any system resources that the replication system may have * acquired and put in the main region. * * Do these now before we free the memory in __os_r_detach. */ if (destroy) { __rep_region_destroy(dbenv); __db_mutex_destroy(&renv->mutex); __db_mutex_destroy(&infop->rp->mutex); } /* * Release the region, and kill our reference. * * We set the DB_ENV->reginfo field to NULL here and discard its memory. * DB_ENV->remove calls __dbenv_remove to do the region remove, and * __dbenv_remove attached and then detaches from the region. We don't * want to return to DB_ENV->remove with a non-NULL DB_ENV->reginfo * field because it will attempt to detach again as part of its cleanup. */ (void)__os_r_detach(dbenv, infop, destroy); if (infop->name != NULL) __os_free(dbenv, infop->name); __os_free(dbenv, dbenv->reginfo); dbenv->reginfo = NULL; return (0);}/* * __db_e_remove -- * Discard an environment if it's not in use. * * PUBLIC: int __db_e_remove __P((DB_ENV *, u_int32_t)); */int__db_e_remove(dbenv, flags) DB_ENV *dbenv; u_int32_t flags;{ REGENV *renv; REGINFO *infop, reginfo; REGION *rp; u_int32_t db_env_reset; int force, ret; force = LF_ISSET(DB_FORCE) ? 1 : 0; /* * This routine has to walk a nasty line between not looking into * the environment (which may be corrupted after an app or system * crash), and removing everything that needs removing. What we * do is: * 1. Connect to the environment (so it better be OK). * 2. If the environment is in use (reference count is non-zero), * return EBUSY. * 3. Overwrite the magic number so that any threads of control * attempting to connect will backoff and retry. * 4. Walk the list of regions. Connect to each region and then * disconnect with the destroy flag set. This shouldn't cause * any problems, even if the region is corrupted, because we * should never be looking inside the region. * 5. Walk the list of files in the directory, unlinking any * files that match a region name. Unlink the environment * file last. * * If the force flag is set, we do not acquire any locks during this * process. */ db_env_reset = F_ISSET(dbenv, DB_ENV_NOLOCKING | DB_ENV_NOPANIC); if (force) F_SET(dbenv, DB_ENV_NOLOCKING); F_SET(dbenv, DB_ENV_NOPANIC); /* Join the environment. */ if ((ret = __db_e_attach(dbenv, NULL)) != 0) { /* * If we can't join it, we assume that's because it doesn't * exist. It would be better to know why we failed, but it * probably isn't important. */ ret = 0; if (force) goto remfiles; goto done; } infop = dbenv->reginfo; renv = infop->primary; /* Lock the environment. */ MUTEX_LOCK(dbenv, &renv->mutex); /* * If it's in use, we're done unless we're forcing the issue or the * environment has panic'd. (Presumably, if the environment panic'd, * the thread holding the reference count may not have cleaned up.) */ if (renv->refcnt == 1 || renv->envpanic == 1 || force) { /* * Set the panic flag and overwrite the magic number. * * !!! * From this point on, there's no going back, we pretty * much ignore errors, and just whack on whatever we can. */ renv->envpanic = 1; renv->magic = 0; /* * Unlock the environment. We should no longer need the lock * because we've poisoned the pool, but we can't continue to * hold it either, because other routines may want it. */ MUTEX_UNLOCK(dbenv, &renv->mutex); /* * Attach to each sub-region and destroy it. * * !!! * The REGION_CREATE_OK flag is set for Windows/95 -- regions * are zero'd out when the last reference to the region goes * away, in which case the underlying OS region code requires * callers be prepared to create the region in order to join it. */ memset(®info, 0, sizeof(reginfo));restart: for (rp = SH_LIST_FIRST(&renv->regionq, __db_region); rp != NULL; rp = SH_LIST_NEXT(rp, q, __db_region)) { if (rp->type == REGION_TYPE_ENV) continue; reginfo.id = rp->id; reginfo.flags = REGION_CREATE_OK; if ((ret = __db_r_attach(dbenv, ®info, 0)) != 0) { __db_err(dbenv, "region %s attach: %s", db_strerror(ret)); continue; } R_UNLOCK(dbenv, ®info); if ((ret = __db_r_detach(dbenv, ®info, 1)) != 0) { __db_err(dbenv, "region detach: %s", db_strerror(ret)); continue; } /* * If we have an error, we continue so we eventually * reach the end of the list. If we succeed, restart * the list because it was relinked when we destroyed * the entry. */ goto restart; } /* Destroy the environment's region. */ (void)__db_e_detach(dbenv, 1); /* Discard any remaining physical files. */remfiles: (void)__db_e_remfile(dbenv); } else { /* Unlock the environment. */ MUTEX_UNLOCK(dbenv, &renv->mutex); /* Discard the environment. */ (void)__db_e_detach(dbenv, 0); ret = EBUSY; }done: F_CLR(dbenv, DB_ENV_NOLOCKING | DB_ENV_NOPANIC); F_SET(dbenv, db_env_reset); return (ret);}/* * __db_e_remfile -- * Discard any region files in the filesystem. */static int__db_e_remfile(dbenv) DB_ENV *dbenv;{ static char *old_region_names[] = { "__db_lock.share", "__db_log.share", "__db_mpool.share", "__db_txn.share", NULL }; int cnt, fcnt, lastrm, ret; u_int8_t saved_byte; const char *dir; char *p, **names, *path, buf[sizeof(DB_REGION_FMT) + 20]; /* Get the full path of a file in the environment. */ (void)snprintf(buf, sizeof(buf), "%s", DB_REGION_ENV); if ((ret = __db_appname(dbenv, DB_APP_NONE, buf, 0, NULL, &path)) != 0) return (ret); /* Get the parent directory for the environment. */ if ((p = __db_rpath(path)) == NULL) { p = path; saved_byte = *p; dir = PATH_DOT; } else { saved_byte = *p; *p = '\0'; dir = path; } /* Get the list of file names. */ if ((ret = __os_dirlist(dbenv, dir, &names, &fcnt)) != 0) __db_err(dbenv, "%s: %s", dir, db_strerror(ret)); /* Restore the path, and free it. */ *p = saved_byte; __os_free(dbenv, path); if (ret != 0) return (ret); /* * Search for valid region names, and remove them. We remove the * environment region last, because it's the key to this whole mess. */ for (lastrm = -1, cnt = fcnt; --cnt >= 0;) { if (strlen(names[cnt]) != DB_REGION_NAME_LENGTH || memcmp(names[cnt], DB_REGION_FMT, DB_REGION_NAME_NUM) != 0) continue; if (strcmp(names[cnt], DB_REGION_ENV) == 0) { lastrm = cnt; continue; } for (p = names[cnt] + DB_REGION_NAME_NUM; *p != '\0' && isdigit((int)*p); ++p) ; if (*p != '\0') continue; if (__db_appname(dbenv, DB_APP_NONE, names[cnt], 0, NULL, &path) == 0) { if (F_ISSET(dbenv, DB_ENV_OVERWRITE)) (void)__db_overwrite(dbenv, path); (void)__os_unlink(dbenv, path); __os_free(dbenv, path); } } if (lastrm != -1) if (__db_appname(dbenv, DB_APP_NONE, names[lastrm], 0, NULL, &path) == 0) { if (F_ISSET(dbenv, DB_ENV_OVERWRITE)) (void)__db_overwrite(dbenv, path); (void)__os_unlink(dbenv, path); __os_free(dbenv, path);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -