lm_fcns.c

来自「db.* (pronounced dee-be star) is an adva」· C语言 代码 · 共 947 行 · 第 1/2 页

C
947
字号
/*************************************************************************** *                                                                         * * db.*                                                                    * * open source database lock manager                                       * *                                                                         * * Copyright (c) 2000 Centura Software Corporation. All rights reserved.   * *                                                                         * * Use of this software, whether in source code format, or in executable,  * * binary object code form, is governed by the CENTURA OPEN SOURCE LICENSE * * which is fully described in the LICENSE.TXT file, included within this  * * distribution of source code files.                                      *  *                                                                         * **************************************************************************/#include "lm.h"/* ======================================================================   Lock all lockable files.*/void lock_all(    LMCB *lmcb){    int       user;    int       ii;    short     locktype;    short     lockstat;    int       qind;    int       qfree;    int       qn;    USERTAB  *ut;    FILETAB  *ft;    QUEUETAB *qt;    QUEUETAB *qprev;    QUEUETAB *qnext;    /* This function enforces an ordering on the lock requests.  A group       lock request is always granted from lowest file reference number to       highest.  For each group request, the lowest numbered un-granted       request must be granted before the next one.  This will allow       deadlock-free locking if each application follows the convention of       making one lock request for all files used within a transaction.            Deadlocks will still be possible if multiple group lock requests are       made within the same transaction.  */    DEBUG1(DB_TEXT("lock_all()\n"));    /* for each user */    for (ut = lmcb->usertab, user = 0; user < lmcb->numusers; user++, ut++) {        /* user not deleted? */        if (!ut->u_name[0])            continue;        /* pending requests? */        if (ut->u_pending == 0)            continue;        /* for each pending request */        for (ft = lmcb->filetab, ii = 0; ii < lmcb->numfiles; ii++, ft++) {            if (!(ii % BITS_PER_BYTE) && !ut->u_req[ii / BITS_PER_BYTE]) {                ii += BITS_PER_BYTE - 1;                continue;            }            if (!is_bit_set(ut->u_req, ii))                continue;            /* This file is requested by this user.  Is this user at the               head of the file's queue?  */            if ((qind = ft->f_queue) == -1)                continue;               /* already granted */            qt = &lmcb->queuetab[qind];            if (qt->q_user != user) {                /* if this user does not already have the lock on this                   file, this is the end of the road */                if (!is_bit_set(ut->u_lock, ii))                    goto nextuser;                /* this is a request bit for a file that is already locked */                continue;            }            else {                /* this user is the first on the file's queue */                locktype = qt->q_locktype;                lockstat = ft->f_lockstat;                /* was this an upgrade request? */                if (locktype == 'W' || locktype == 'X')                    locktype = (short) tolower(locktype);                /* if this request is for a lock that is already held only                   by this user */                if ((lockstat == 'w' || lockstat == 'x') &&                        is_bit_set(ut->u_lock, ii)) {                    /* Give the user the lock he already has the access to.                       This may be a downgrade to read.  */                    grant_lock(lmcb, user, ii, locktype);                }                /* else if the the file is free, read locked, or Record                   locked, and the first queued request is a read lock */                else if ((lockstat == 'f' || lockstat == 'r' ||                        lockstat == 'R') && locktype == 'r') {                    /* give this lock to the waiting user */                    grant_lock(lmcb, user, ii, 'r');                    /* Scan the LRQ for other 'r' lock req [591] */                    qprev = qt;                    qn = qt->q_next;                    while (qn != -1) {                        qnext = &lmcb->queuetab[qn];                        /* Stop when we encounter a non-read lock req */                        if (qt->q_locktype != 'r')                            break;                        if (qt->q_user > user) {                            qprev = qnext;                            qn = qnext->q_next;                            continue;                        }                        /* Here's another read lock we can grant */                        grant_lock(lmcb, qnext->q_user, ii, 'r');                        /* Remove this request from queue */                        qprev->q_next = qnext->q_next;                        qfree = qn;                        qn = qnext->q_next;                        free_q(lmcb, qfree);                    }                }                /* else if the file is free or read locked, and the first                   queued request is a Record lock */                else if ((lockstat == 'f' || lockstat == 'r') &&                        locktype == 'R') {                    /* grant the Record lock */                    grant_lock(lmcb, user, ii, locktype);                }                /* else if the file is free, and the first queued request                   is a write or exclusive lock */                else if (lockstat == 'f' && (locktype == 'w' ||                        locktype == 'x')) {                    /* grant the write lock */                    grant_lock(lmcb, user, ii, locktype);                }                /* else if the file is read locked, and the first queued                   request is a write or exclusive lock */                else if (lockstat == 'r' && (locktype == 'w' ||                        locktype == 'x')) {                    int set;                    /* see if this is the only holder of the read lock */                    set = is_bit_set(ft->f_lock, user);                    if (set)                        bit_clr(ft->f_lock, user);                    if (is_map_zero(ft->f_lock, lmcb->userbmbytes))                        grant_lock(lmcb, user, ii, locktype);                    else {                        /* not lockable */                        if (set)                            bit_set(ft->f_lock, user);                        goto nextuser;                    }                }                /* else not lockable */                else                    goto nextuser;                /* discard this queue entry */                ft->f_queue = qt->q_next;                free_q(lmcb, qind);            }        }nextuser:        continue;    }}/* ======================================================================   Grant a lock request to one user*/void grant_lock(    LMCB *lmcb,    int   user,    int   file,    short type){    USERTAB *ut = &lmcb->usertab[user];    FILETAB *ft = &lmcb->filetab[file];    DEBUG4(DB_TEXT("\tgrant_lock(user=%d, file=%d, type=%c)\n"), user, file,            type)    /* set the corresponding bits */    bit_set(ft->f_lock, user);    bit_set(ut->u_lock, file);    /* set the lock status */    if (ft->f_lockstat != 'R')        ft->f_lockstat = type;    /* update the lock request status for this user:       u_pending == 0 && u_waiting > 0 indicates that this user is now       ready to get its reply    */    ut->u_pending--;    ut->u_waiting++;}/* ======================================================================   Free one file lock*/void freelock(    LMCB *lmcb,    int   user,    int   file){    USERTAB *ut = &lmcb->usertab[user];    FILETAB *ft = &lmcb->filetab[file];    DEBUG3(DB_TEXT("\tfreelock(user=%d, file=%d)\n"), user, file)    /* remove the file and user lock bits */    bit_clr(ft->f_lock, user);    bit_clr(ut->u_lock, file);    /* if this is a Record locked file */    if (ft->f_lockstat == 'R')    {        /* if there are now no read locks, unlock this file */        if (is_map_zero(ft->f_lock, lmcb->userbmbytes))        {            lmcb->locks_freed++;            ft->f_lockstat = 'f';        }        else            ft->f_lockstat = 'r';    }    else    {        /* if there are now no locks, unlock this file */        if (is_map_zero(ft->f_lock, lmcb->userbmbytes))        {            lmcb->locks_freed++;            ft->f_lockstat = 'f';        }    }}/* ======================================================================   Close one file*/void close_file(    LMCB *lmcb,    int   user,    int   file){    USERTAB *ut = &lmcb->usertab[user];    FILETAB *ft = &lmcb->filetab[file];    DEBUG3(DB_TEXT("\tclose_file(user=%d, file=%d)\n"), user, file)    /* remove the bits between file and user */    bit_clr(ft->f_open, user);    bit_clr(ut->u_open, file);    /* if this was the last user holding the file open, remove the entry */    if (is_map_zero(ft->f_open, lmcb->userbmbytes))    {        fileid_del(lmcb->fidtab, ft->f_index);        ft->f_index = -1;        memset(ft->f_open, 0, lmcb->userbmbytes);        memset(ft->f_lock, 0, lmcb->userbmbytes);        adj_files(lmcb);        DEBUG2(DB_TEXT("\t\talso removing %d from filetab\n"), file)    }}/* ======================================================================   Close a user entry*/void close_user(    LMCB *lmcb,    int   user){    int      taf;    USERTAB *ut = &lmcb->usertab[user];    TAFTAB  *tt;    DEBUG2(DB_TEXT("close_user(user=%d)\n"), user)    if (ut->u_conn != NULL) {        (*lmcb->discon)(ut->u_conn);        ut->u_conn = NULL;    }    /* If the user still has files open, then the name is to remain in the       table, because he is supposed to come back later, re-open the files       and free them then. */    if (!is_map_zero(ut->u_open, lmcb->filebmbytes)) {        ut->u_status = U_HOLDING_X;        return;    }    DEBUG2(DB_TEXT("\tremoving user %d\n"), user);    ut->u_status = U_EMPTY;    if (ut->u_pending)        free_pending(lmcb, user);    if ((taf = ut->u_taf) != -1) {        tt = &lmcb->taftab[taf];        if (--tt->t_nusers == 0) {            fileid_del(lmcb->fidtab, tt->t_index);            tt->t_index = -1;            tt->t_status = REC_OKAY;            tt->t_recuser = -1;        }    }    ut->u_name[0] = 0;    ut->u_taf = -1;    /* If this is the last user, decrease the list size */    adj_users(lmcb);    adj_tafs(lmcb);}/* ======================================================================   Mark a user entry as dead*/void dead_user(    LMCB *lmcb,    int   user,    int   kill){    int      ii;    int      excl;    int      dead_user;    USERTAB *ut = &lmcb->usertab[user];    USERTAB *dt;    FILETAB *ft;    TAFTAB  *tt = NULL;    if (user == -1) {        DEBUG1(DB_TEXT("dead_user(-1)\n"))        return;    }    DEBUG2(DB_TEXT("dead_user(user=%s)\n"), ut->u_name)    DEBUG2(DB_TEXT("\tuser = %d\n"), user)    excl = 0;    for (ft = lmcb->filetab, ii = 0; ii < lmcb->numfiles; ii++, ft++) {        if (is_bit_set(ut->u_lock, ii)) {            if (toupper(ft->f_lockstat) == 'R')                freelock(lmcb, user, ii);            if (ft->f_lockstat == 'x') {                if (kill)                    freelock(lmcb, user, ii);                else                    excl = 1;            }            if (ft->f_lockstat == 'f')                close_file(lmcb, user, ii);        }    }    free_pending(lmcb, user);    DEBUG2(DB_TEXT("\tafter lock checks, excl = %d\n"), excl);    DEBUG3(DB_TEXT("\t\tlogfile = '%s', ucount = %d\n"),            fileid_get(lmcb->fidtab, ut->u_logfile), usercount(lmcb));    if (ut->u_conn != NULL) {        (*lmcb->discon)(ut->u_conn);        ut->u_conn = NULL;    }    /* if there is a log file, and other users to do recovery */    if (ut->u_taf != -1)        tt = &lmcb->taftab[ut->u_taf];    if (ut->u_logfile != -1 && (usercount(lmcb) > 1 || excl)) {        ut->u_status = U_DEAD;        if (ut->u_taf != -1) {            tt->t_status = REC_NEEDED;            tt->t_recuser = user;        }        DEBUG1(DB_TEXT("\tUser died during commit, marked as needing recovery\n"));    }    else {        if (ut->u_status == U_RECOVERING) {            DEBUG3(DB_TEXT("\tUser died during recovery: user = %d, recuser = %d\n"),                    user, ut->u_recuser);            /* transfer the log file back to the original dead user */            if ((dead_user = ut->u_recuser) != user) {                ft = lmcb->filetab;                for (ii = 0; ii < lmcb->numfiles; ii++, ft++) {                    if (!is_bit_set(ut->u_open, ii))                        continue;                    if (is_bit_set(ut->u_lock, ii)) {                        if (ft->f_lockstat != 'x') {                            freelock(lmcb, user, ii);                            close_file(lmcb, user, ii);                        }                    }                    else                        close_file(lmcb, user, ii);                }                close_user(lmcb, user);            }            dt = &lmcb->usertab[dead_user];            dt->u_status = U_DEAD;            if (dt->u_taf != -1) {                lmcb->taftab[dt->u_taf].t_status = REC_NEEDED;                lmcb->taftab[dt->u_taf].t_recuser = dead_user;            }        }        else {            DEBUG2(DB_TEXT("\tUser died in non-critical state=%d\n"),                    ut->u_status);            clear_user(lmcb, user);            /* If this is an exclusive file lock holder who is quitting for               the day, mark it so that it can be picked up again */            if (excl)                ut->u_status = U_HOLDING_X;            DEBUG2(DB_TEXT("\tUsers new state = %d\n"), ut->u_status);            /* Having cleared out a dead-user, see if locks can be granted */            lock_all(lmcb);        }    }}#if 0/* ======================================================================   Mark as dead the user entry corresponding to specified connection*/void dead_connection(LMCB *lmcb, int conn){   int i;#ifdef DB_DEBUG   lm_printf(DB_TEXT("\nDead User detected, connection %d\n"), conn);#endif   for (i = 0; i < maxusers; i++)   {      if (usertab[i].u_conn == conn)      {         dead_user(i, 0);         return;      }   }}#endif/* ======================================================================

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?