253 lines
6.9 KiB
C
253 lines
6.9 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2009 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_string.h"
|
|
|
|
#include "copy.h"
|
|
#include "gdsroot.h"
|
|
#include "gdsblk.h"
|
|
#include "gtm_facility.h"
|
|
#include "fileinfo.h"
|
|
#include "gdsbt.h"
|
|
#include "gdsfhead.h"
|
|
#include "mlkdef.h"
|
|
#include "locklits.h"
|
|
#include "error.h"
|
|
#include "rc.h"
|
|
#include "gtcm.h"
|
|
#include "mlk_pvtblk_delete.h"
|
|
#include "mlk_unlock.h"
|
|
#include "mlk_pvtblk_insert.h"
|
|
#include "lckclr.h"
|
|
#include "mlk_lock.h"
|
|
#include "mlk_bckout.h"
|
|
|
|
GBLREF UINTPTR_T rc_auxown; /* From server, address to use in auxown field, same as OMI */
|
|
GBLREF unsigned short lks_this_cmd;
|
|
GBLREF mlk_pvtblk *mlk_pvt_root;
|
|
GBLREF int omi_pid;
|
|
GBLREF gd_region *gv_cur_region;
|
|
GBLREF sgmnt_addrs *cs_addrs;
|
|
|
|
#define KEY_BUFF_SIZE 1024
|
|
|
|
int rc_prc_lock(rc_q_hdr *qhdr)
|
|
{
|
|
rc_req_lock *req;
|
|
rc_sbkey *sbk;
|
|
short i, len, pid_len;
|
|
mval lock, ext;
|
|
mlk_pvtblk **prior, *mp, *x;
|
|
rc_lknam *fl;
|
|
unsigned char action;
|
|
bool blocked;
|
|
char key_buff[KEY_BUFF_SIZE], *lkname;
|
|
unsigned char buff[12], *cp;
|
|
short subcnt;
|
|
int in_pid, locks_done, temp;
|
|
|
|
ESTABLISH_RET(rc_dbms_ch, RC_SUCCESS);
|
|
/* Clean up dead locks in private list */
|
|
for (prior = &mlk_pvt_root; *prior; )
|
|
{ if (!(*prior)->granted || !(*prior)->nodptr || (*prior)->nodptr->owner != omi_pid)
|
|
mlk_pvtblk_delete(prior);
|
|
else
|
|
{ (*prior)->trans = 0;
|
|
prior = &(*prior)->next;
|
|
}
|
|
}
|
|
|
|
req = (rc_req_lock *)qhdr;
|
|
in_pid = ((qhdr->r.pid1.value << 16) | qhdr->r.pid2.value);
|
|
cp = i2asc(buff,in_pid);
|
|
pid_len = cp - buff;
|
|
lks_this_cmd = 0;
|
|
if (req->hdr.r.fmd.value & RC_MODE_CLEARLOCK)
|
|
{ /* Loop through all the locks, unlocking ones that belong to this client */
|
|
for (prior = &mlk_pvt_root; *prior; )
|
|
{ if ((*prior)->nodptr->auxowner == rc_auxown
|
|
&& pid_len == (*prior)->value[(*prior)->total_length]
|
|
&& !memcmp(&(*prior)->value[(*prior)->total_length+1],
|
|
buff,pid_len))
|
|
{ mlk_unlock(*prior);
|
|
mlk_pvtblk_delete(prior);
|
|
}else
|
|
prior = &(*prior)->next;
|
|
}
|
|
action = LOCKED;
|
|
} else if (req->hdr.r.fmd.value & RC_MODE_DECRLOCK)
|
|
{ sbk = &req->dlocks[0].sb_key;
|
|
fl = req->dlocks;
|
|
|
|
/* Loop through all requested locks */
|
|
for ( i = 0; i < req->nlocks.value; i++)
|
|
{
|
|
if ((char *) fl - (char *) req + sbk->len.value + 1 > req->hdr.r.len.value)
|
|
{ /* we are beyond the end of this packet and still have
|
|
* lock requests to process. Bad packet.
|
|
*/
|
|
qhdr->a.erc.value = RC_BADXBUF;
|
|
REVERT;
|
|
#ifdef DEBUG
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Bad Rq: Invalid nLockNames value.");
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if ((temp = rc_frmt_lck(key_buff, KEY_BUFF_SIZE, (unsigned char *)sbk->key, sbk->len.value, &subcnt)) < 0)
|
|
{
|
|
temp = -temp;
|
|
qhdr->a.erc.value = temp;
|
|
REVERT;
|
|
|
|
#ifdef DEBUG
|
|
if (temp == RC_KEYTOOLONG)
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");
|
|
else
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Invalid lock request.");
|
|
#endif
|
|
return -1;
|
|
}
|
|
temp += subcnt;
|
|
|
|
/* Loop through all owned locks looking for requested one */
|
|
for (prior = &mlk_pvt_root; *prior; )
|
|
{ if ((*prior)->nodptr->auxowner == rc_auxown
|
|
&& temp == (*prior)->total_length
|
|
&& !memcmp(&(*prior)->value[0],key_buff,temp)
|
|
&& pid_len == (*prior)->value[(*prior)->total_length]
|
|
&& !memcmp(&(*prior)->value[(*prior)->total_length+1],
|
|
buff,pid_len))
|
|
{ (*prior)->level -= 1;
|
|
if (!(*prior)->level)
|
|
{ mlk_unlock(*prior);
|
|
mlk_pvtblk_delete(prior);
|
|
}
|
|
}else
|
|
prior = &(*prior)->next;
|
|
}
|
|
fl = (rc_lknam*)((char *)fl + sbk->len.value - 1 + SIZEOF(rc_lknam));
|
|
sbk = &fl->sb_key;
|
|
|
|
}
|
|
qhdr->a.erc.value = RC_SUCCESS;
|
|
REVERT;
|
|
return 0;
|
|
} else
|
|
action = INCREMENTAL;
|
|
lock.mvtype = ext.mvtype = MV_STR;
|
|
lkname = (char*)req->dlocks[0].sb_key.key;
|
|
sbk = &req->dlocks[0].sb_key;
|
|
fl = req->dlocks;
|
|
for ( i = 0; i < req->nlocks.value; i++)
|
|
{
|
|
if ((char *) fl - (char *) req + sbk->len.value + 1 > req->hdr.r.len.value)
|
|
{ /* we are beyond the end of this packet and still have
|
|
* lock requests to process. Bad packet.
|
|
*/
|
|
qhdr->a.erc.value = RC_BADXBUF;
|
|
REVERT;
|
|
#ifdef DEBUG
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Bad Rq: Invalid nLockNames value.");
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if ((qhdr->a.erc.value = rc_fnd_file(&fl->xdsid)) != RC_SUCCESS)
|
|
{
|
|
REVERT;
|
|
#ifdef DEBUG
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"rc_fnd_file failed.");
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if ((temp = rc_frmt_lck(key_buff, KEY_BUFF_SIZE, (unsigned char *)sbk->key, sbk->len.value, &subcnt)) < 0)
|
|
{
|
|
temp = -temp;
|
|
qhdr->a.erc.value = temp;
|
|
REVERT;
|
|
#ifdef DEBUG
|
|
if (temp == RC_KEYTOOLONG)
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_KEYTOOLONG.");
|
|
else
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"Invalid lock request.");
|
|
#endif
|
|
return -1;
|
|
}
|
|
temp += subcnt;
|
|
mp = (mlk_pvtblk*)malloc(SIZEOF(mlk_pvtblk) + temp + pid_len + 1);
|
|
memset(mp, 0, SIZEOF(mlk_pvtblk) - 1);
|
|
mp->subscript_cnt = subcnt;
|
|
mp->total_length = temp;
|
|
memcpy(mp->value, key_buff, mp->total_length);
|
|
mp->region = gv_cur_region;
|
|
mp->ctlptr = (mlk_ctldata*)cs_addrs->lock_addrs[0];
|
|
mp->value[mp->total_length] = pid_len;
|
|
memcpy(&mp->value[mp->total_length + 1], buff, pid_len);
|
|
if (!mlk_pvtblk_insert(mp))
|
|
{ if (!(mp->value[mp->total_length] == mlk_pvt_root->value[mlk_pvt_root->total_length]
|
|
&& !memcmp(&mp->value[mp->total_length + 1], &mlk_pvt_root->value[mp->total_length + 1],
|
|
mp->total_length + 1)))
|
|
{ free(mp); /* Server owns lock on behalf of a different agent/client pair */
|
|
REVERT;
|
|
qhdr->a.erc.value = RC_LOCKCONFLICT;
|
|
return 0; /* Return lock not granted */
|
|
}
|
|
free(mp);
|
|
} else if (mp != mlk_pvt_root)
|
|
{ REVERT;
|
|
qhdr->a.erc.value = RC_GLOBERRUNSPEC;
|
|
#ifdef DEBUG
|
|
gtcm_cpktdmp((char *)qhdr,qhdr->a.len.value,"RC_GLOBERRUNSPEC.");
|
|
#endif
|
|
return -1;/* error */
|
|
|
|
}
|
|
fl = (rc_lknam*)((char *)fl + sbk->len.value - 1 + SIZEOF(rc_lknam));
|
|
sbk = &fl->sb_key;
|
|
}
|
|
blocked = FALSE;
|
|
lckclr();
|
|
for (x = mlk_pvt_root, locks_done = 0; locks_done < lks_this_cmd; x = x->next)
|
|
{
|
|
locks_done++;
|
|
/* If lock is obtained */
|
|
if (!mlk_lock(x,rc_auxown,TRUE))
|
|
{
|
|
x->granted = TRUE;
|
|
if (action == INCREMENTAL)
|
|
x->level += x->translev;
|
|
else
|
|
x->level = 1;
|
|
} else
|
|
{
|
|
blocked = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (blocked) /* need to back out all locks */
|
|
{
|
|
for (x = mlk_pvt_root, i = 0;
|
|
i < locks_done ; x = x->next, i++)
|
|
{
|
|
mlk_bckout(x, action);
|
|
}
|
|
qhdr->a.erc.value = RC_LOCKCONFLICT;
|
|
} else
|
|
qhdr->a.erc.value = RC_SUCCESS;
|
|
REVERT;
|
|
return 0;
|
|
}
|
|
|