tcl_lock.c 17.2 KB
Newer Older
1 2 3
/*-
 * See the file LICENSE for redistribution information.
 *
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
4
 * Copyright (c) 1999-2001
5 6 7 8 9 10
 *	Sleepycat Software.  All rights reserved.
 */

#include "db_config.h"

#ifndef lint
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
11
static const char revid[] = "$Id: tcl_lock.c,v 11.47 2002/08/08 15:27:10 bostic Exp $";
12 13 14 15 16 17 18 19 20 21 22
#endif /* not lint */

#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>

#include <stdlib.h>
#include <string.h>
#include <tcl.h>
#endif

#include "db_int.h"
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
23
#include "dbinc/tcl_db.h"
24 25 26 27 28 29 30 31 32 33

/*
 * Prototypes for procedures defined later in this file:
 */
static int      lock_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
static int	_LockMode __P((Tcl_Interp *, Tcl_Obj *, db_lockmode_t *));
static int	_GetThisLock __P((Tcl_Interp *, DB_ENV *, u_int32_t,
				     u_int32_t, DBT *, db_lockmode_t, char *));
static void	_LockPutInfo __P((Tcl_Interp *, db_lockop_t, DB_LOCK *,
				     u_int32_t, DBT *));
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
34
#if CONFIG_TEST
35
static char *lkmode[] = {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
36 37 38 39 40 41
	"ng",
	"read",
	"write",
	"iwrite",
	"iread",
	"iwr",
42 43 44
	 NULL
};
enum lkmode {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
45 46 47 48 49 50
	LK_NG,
	LK_READ,
	LK_WRITE,
	LK_IWRITE,
	LK_IREAD,
	LK_IWR
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
};

/*
 * tcl_LockDetect --
 *
 * PUBLIC: int tcl_LockDetect __P((Tcl_Interp *, int,
 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
 */
int
tcl_LockDetect(interp, objc, objv, envp)
	Tcl_Interp *interp;		/* Interpreter */
	int objc;			/* How many arguments? */
	Tcl_Obj *CONST objv[];		/* The argument objects */
	DB_ENV *envp;			/* Environment pointer */
{
	static char *ldopts[] = {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
67
		"expire",
68
		"default",
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
69 70 71
		"maxlocks",
		"minlocks",
		"minwrites",
72 73 74 75 76 77
		"oldest",
		"random",
		"youngest",
		 NULL
	};
	enum ldopts {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
78
		LD_EXPIRE,
79
		LD_DEFAULT,
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
80 81 82
		LD_MAXLOCKS,
		LD_MINLOCKS,
		LD_MINWRITES,
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
		LD_OLDEST,
		LD_RANDOM,
		LD_YOUNGEST
	};
	u_int32_t flag, policy;
	int i, optindex, result, ret;

	result = TCL_OK;
	flag = policy = 0;
	i = 2;
	while (i < objc) {
		if (Tcl_GetIndexFromObj(interp, objv[i],
		    ldopts, "option", TCL_EXACT, &optindex) != TCL_OK)
			return (IS_HELP(objv[i]));
		i++;
		switch ((enum ldopts)optindex) {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
99 100 101 102
		case LD_EXPIRE:
			FLAG_CHECK(policy);
			policy = DB_LOCK_EXPIRE;
			break;
103 104 105 106
		case LD_DEFAULT:
			FLAG_CHECK(policy);
			policy = DB_LOCK_DEFAULT;
			break;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
107 108 109 110 111 112 113 114 115 116 117 118
		case LD_MAXLOCKS:
			FLAG_CHECK(policy);
			policy = DB_LOCK_MAXLOCKS;
			break;
		case LD_MINWRITES:
			FLAG_CHECK(policy);
			policy = DB_LOCK_MINWRITE;
			break;
		case LD_MINLOCKS:
			FLAG_CHECK(policy);
			policy = DB_LOCK_MINLOCKS;
			break;
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
		case LD_OLDEST:
			FLAG_CHECK(policy);
			policy = DB_LOCK_OLDEST;
			break;
		case LD_YOUNGEST:
			FLAG_CHECK(policy);
			policy = DB_LOCK_YOUNGEST;
			break;
		case LD_RANDOM:
			FLAG_CHECK(policy);
			policy = DB_LOCK_RANDOM;
			break;
		}
	}

	_debug_check();
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
135 136
	ret = envp->lock_detect(envp, flag, policy, NULL);
	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock detect");
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
	return (result);
}

/*
 * tcl_LockGet --
 *
 * PUBLIC: int tcl_LockGet __P((Tcl_Interp *, int,
 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
 */
int
tcl_LockGet(interp, objc, objv, envp)
	Tcl_Interp *interp;		/* Interpreter */
	int objc;			/* How many arguments? */
	Tcl_Obj *CONST objv[];		/* The argument objects */
	DB_ENV *envp;			/* Environment pointer */
{
	static char *lgopts[] = {
		"-nowait",
		 NULL
	};
	enum lgopts {
		LGNOWAIT
	};
	DBT obj;
	Tcl_Obj *res;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
162
	void *otmp;
163 164
	db_lockmode_t mode;
	u_int32_t flag, lockid;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
165
	int freeobj, optindex, result, ret;
166 167 168
	char newname[MSG_SIZE];

	result = TCL_OK;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
169
	freeobj = 0;
170 171 172 173 174 175 176 177 178 179 180 181 182 183
	memset(newname, 0, MSG_SIZE);
	if (objc != 5 && objc != 6) {
		Tcl_WrongNumArgs(interp, 2, objv, "?-nowait? mode id obj");
		return (TCL_ERROR);
	}
	/*
	 * Work back from required args.
	 * Last arg is obj.
	 * Second last is lock id.
	 * Third last is lock mode.
	 */
	memset(&obj, 0, sizeof(obj));

	if ((result =
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
184
	    _GetUInt32(interp, objv[objc-2], &lockid)) != TCL_OK)
185 186
		return (result);

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
187 188 189 190 191
	ret = _CopyObjBytes(interp, objv[objc-1], &otmp,
	    &obj.size, &freeobj);
	if (ret != 0) {
		result = _ReturnSetup(interp, ret,
		    DB_RETOK_STD(ret), "lock get");
192
		return (result);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
193 194 195 196
	}
	obj.data = otmp;
	if ((result = _LockMode(interp, objv[(objc - 3)], &mode)) != TCL_OK)
		goto out;
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217

	/*
	 * Any left over arg is the flag.
	 */
	flag = 0;
	if (objc == 6) {
		if (Tcl_GetIndexFromObj(interp, objv[(objc - 4)],
		    lgopts, "option", TCL_EXACT, &optindex) != TCL_OK)
			return (IS_HELP(objv[(objc - 4)]));
		switch ((enum lgopts)optindex) {
		case LGNOWAIT:
			flag |= DB_LOCK_NOWAIT;
			break;
		}
	}

	result = _GetThisLock(interp, envp, lockid, flag, &obj, mode, newname);
	if (result == TCL_OK) {
		res = Tcl_NewStringObj(newname, strlen(newname));
		Tcl_SetObjResult(interp, res);
	}
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
218 219 220
out:
	if (freeobj)
		(void)__os_free(envp, otmp);
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
	return (result);
}

/*
 * tcl_LockStat --
 *
 * PUBLIC: int tcl_LockStat __P((Tcl_Interp *, int,
 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
 */
int
tcl_LockStat(interp, objc, objv, envp)
	Tcl_Interp *interp;		/* Interpreter */
	int objc;			/* How many arguments? */
	Tcl_Obj *CONST objv[];		/* The argument objects */
	DB_ENV *envp;			/* Environment pointer */
{
	DB_LOCK_STAT *sp;
	Tcl_Obj *res;
	int result, ret;

	result = TCL_OK;
	/*
	 * No args for this.  Error if there are some.
	 */
	if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, NULL);
		return (TCL_ERROR);
	}
	_debug_check();
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
250 251
	ret = envp->lock_stat(envp, &sp, 0);
	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock stat");
252 253 254 255 256 257 258 259 260 261 262
	if (result == TCL_ERROR)
		return (result);
	/*
	 * Have our stats, now construct the name value
	 * list pairs and free up the memory.
	 */
	res = Tcl_NewObj();
	/*
	 * MAKE_STAT_LIST assumes 'res' and 'error' label.
	 */
	MAKE_STAT_LIST("Region size", sp->st_regsize);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
263 264 265 266 267
	MAKE_STAT_LIST("Last allocated locker ID", sp->st_id);
	MAKE_STAT_LIST("Current maximum unused locker ID", sp->st_cur_maxid);
	MAKE_STAT_LIST("Maximum locks", sp->st_maxlocks);
	MAKE_STAT_LIST("Maximum lockers", sp->st_maxlockers);
	MAKE_STAT_LIST("Maximum objects", sp->st_maxobjects);
268 269 270 271 272 273 274 275 276 277
	MAKE_STAT_LIST("Lock modes", sp->st_nmodes);
	MAKE_STAT_LIST("Current number of locks", sp->st_nlocks);
	MAKE_STAT_LIST("Maximum number of locks so far", sp->st_maxnlocks);
	MAKE_STAT_LIST("Current number of lockers", sp->st_nlockers);
	MAKE_STAT_LIST("Maximum number of lockers so far", sp->st_maxnlockers);
	MAKE_STAT_LIST("Current number of objects", sp->st_nobjects);
	MAKE_STAT_LIST("Maximum number of objects so far", sp->st_maxnobjects);
	MAKE_STAT_LIST("Number of conflicts", sp->st_nconflicts);
	MAKE_STAT_LIST("Lock requests", sp->st_nrequests);
	MAKE_STAT_LIST("Lock releases", sp->st_nreleases);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
278
	MAKE_STAT_LIST("Lock requests that would have waited", sp->st_nnowaits);
279 280 281
	MAKE_STAT_LIST("Deadlocks detected", sp->st_ndeadlocks);
	MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
	MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
282 283 284 285
	MAKE_STAT_LIST("Lock timeout value", sp->st_locktimeout);
	MAKE_STAT_LIST("Number of lock timeouts", sp->st_nlocktimeouts);
	MAKE_STAT_LIST("Transaction timeout value", sp->st_txntimeout);
	MAKE_STAT_LIST("Number of transaction timeouts", sp->st_ntxntimeouts);
286 287
	Tcl_SetObjResult(interp, res);
error:
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	free(sp);
	return (result);
}

/*
 * tcl_LockTimeout --
 *
 * PUBLIC: int tcl_LockTimeout __P((Tcl_Interp *, int,
 * PUBLIC:    Tcl_Obj * CONST*, DB_ENV *));
 */
int
tcl_LockTimeout(interp, objc, objv, envp)
	Tcl_Interp *interp;		/* Interpreter */
	int objc;			/* How many arguments? */
	Tcl_Obj *CONST objv[];		/* The argument objects */
	DB_ENV *envp;			/* Environment pointer */
{
	long timeout;
	int result, ret;

	/*
	 * One arg, the timeout.
	 */
	if (objc != 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "?timeout?");
		return (TCL_ERROR);
	}
	result = Tcl_GetLongFromObj(interp, objv[2], &timeout);
	if (result != TCL_OK)
		return (result);
	_debug_check();
	ret = envp->set_timeout(envp, (u_int32_t)timeout, DB_SET_LOCK_TIMEOUT);
	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock timeout");
321 322 323 324 325 326 327 328 329
	return (result);
}

/*
 * lock_Cmd --
 *	Implements the "lock" widget.
 */
static int
lock_Cmd(clientData, interp, objc, objv)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
330 331 332 333
	ClientData clientData;		/* Lock handle */
	Tcl_Interp *interp;		/* Interpreter */
	int objc;			/* How many arguments? */
	Tcl_Obj *CONST objv[];		/* The argument objects */
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
{
	static char *lkcmds[] = {
		"put",
		NULL
	};
	enum lkcmds {
		LKPUT
	};
	DB_ENV *env;
	DB_LOCK *lock;
	DBTCL_INFO *lkip;
	int cmdindex, result, ret;

	Tcl_ResetResult(interp);
	lock = (DB_LOCK *)clientData;
	lkip = _PtrToInfo((void *)lock);
	result = TCL_OK;

	if (lock == NULL) {
		Tcl_SetResult(interp, "NULL lock", TCL_STATIC);
		return (TCL_ERROR);
	}
	if (lkip == NULL) {
		Tcl_SetResult(interp, "NULL lock info pointer", TCL_STATIC);
		return (TCL_ERROR);
	}

	env = NAME_TO_ENV(lkip->i_parent->i_name);
	/*
	 * No args for this.  Error if there are some.
	 */
	if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, NULL);
		return (TCL_ERROR);
	}
	/*
	 * Get the command name index from the object based on the dbcmds
	 * defined above.
	 */
	if (Tcl_GetIndexFromObj(interp,
	    objv[1], lkcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
		return (IS_HELP(objv[1]));

	switch ((enum lkcmds)cmdindex) {
	case LKPUT:
		_debug_check();
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
380 381 382
		ret = env->lock_put(env, lock);
		result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
		    "lock put");
383 384
		(void)Tcl_DeleteCommand(interp, lkip->i_name);
		_DeleteInfo(lkip);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
385
		__os_free(env, lock);
386 387 388 389 390 391 392 393 394 395 396 397
		break;
	}
	return (result);
}

/*
 * tcl_LockVec --
 *
 * PUBLIC: int tcl_LockVec __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_ENV *));
 */
int
tcl_LockVec(interp, objc, objv, envp)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
398 399 400
	Tcl_Interp *interp;		/* Interpreter */
	int objc;			/* How many arguments? */
	Tcl_Obj *CONST objv[];		/* The argument objects */
401 402 403 404 405 406 407 408 409 410
	DB_ENV *envp;			/* environment pointer */
{
	static char *lvopts[] = {
		"-nowait",
		 NULL
	};
	enum lvopts {
		LVNOWAIT
	};
	static char *lkops[] = {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
411 412 413 414 415
		"get",
		"put",
		"put_all",
		"put_obj",
		"timeout",
416 417 418
		 NULL
	};
	enum lkops {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
419 420 421 422 423
		LKGET,
		LKPUT,
		LKPUTALL,
		LKPUTOBJ,
		LKTIMEOUT
424 425 426 427 428
	};
	DB_LOCK *lock;
	DB_LOCKREQ list;
	DBT obj;
	Tcl_Obj **myobjv, *res, *thisop;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
429
	void *otmp;
430
	u_int32_t flag, lockid;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
431
	int freeobj, i, myobjc, optindex, result, ret;
432 433 434 435 436
	char *lockname, msg[MSG_SIZE], newname[MSG_SIZE];

	result = TCL_OK;
	memset(newname, 0, MSG_SIZE);
	flag = 0;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
437 438
	freeobj = 0;

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	/*
	 * If -nowait is given, it MUST be first arg.
	 */
	if (Tcl_GetIndexFromObj(interp, objv[2],
	    lvopts, "option", TCL_EXACT, &optindex) == TCL_OK) {
		switch ((enum lvopts)optindex) {
		case LVNOWAIT:
			flag |= DB_LOCK_NOWAIT;
			break;
		}
		i = 3;
	} else {
		if (IS_HELP(objv[2]) == TCL_OK)
			return (TCL_OK);
		Tcl_ResetResult(interp);
		i = 2;
	}

	/*
	 * Our next arg MUST be the locker ID.
	 */
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
460
	result = _GetUInt32(interp, objv[i++], &lockid);
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
	if (result != TCL_OK)
		return (result);

	/*
	 * All other remaining args are operation tuples.
	 * Go through sequentially to decode, execute and build
	 * up list of return values.
	 */
	res = Tcl_NewListObj(0, NULL);
	while (i < objc) {
		/*
		 * Get the list of the tuple.
		 */
		lock = NULL;
		result = Tcl_ListObjGetElements(interp, objv[i],
		    &myobjc, &myobjv);
		if (result == TCL_OK)
			i++;
		else
			break;
		/*
		 * First we will set up the list of requests.
		 * We will make a "second pass" after we get back
		 * the results from the lock_vec call to create
		 * the return list.
		 */
		if (Tcl_GetIndexFromObj(interp, myobjv[0],
		    lkops, "option", TCL_EXACT, &optindex) != TCL_OK) {
			result = IS_HELP(myobjv[0]);
			goto error;
		}
		switch ((enum lkops)optindex) {
		case LKGET:
			if (myobjc != 3) {
				Tcl_WrongNumArgs(interp, 1, myobjv,
				    "{get obj mode}");
				result = TCL_ERROR;
				goto error;
			}
			result = _LockMode(interp, myobjv[2], &list.mode);
			if (result != TCL_OK)
				goto error;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
503 504 505 506 507 508 509 510
			ret = _CopyObjBytes(interp, myobjv[1], &otmp,
			    &obj.size, &freeobj);
			if (ret != 0) {
				result = _ReturnSetup(interp, ret,
				    DB_RETOK_STD(ret), "lock vec");
				return (result);
			}
			obj.data = otmp;
511 512 513
			ret = _GetThisLock(interp, envp, lockid, flag,
			    &obj, list.mode, newname);
			if (ret != 0) {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
514 515
				result = _ReturnSetup(interp, ret,
				    DB_RETOK_STD(ret), "lock vec");
516 517 518 519 520 521 522
				thisop = Tcl_NewIntObj(ret);
				(void)Tcl_ListObjAppendElement(interp, res,
				    thisop);
				goto error;
			}
			thisop = Tcl_NewStringObj(newname, strlen(newname));
			(void)Tcl_ListObjAppendElement(interp, res, thisop);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
523 524 525 526
			if (freeobj) {
				(void)__os_free(envp, otmp);
				freeobj = 0;
			}
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
			continue;
		case LKPUT:
			if (myobjc != 2) {
				Tcl_WrongNumArgs(interp, 1, myobjv,
				    "{put lock}");
				result = TCL_ERROR;
				goto error;
			}
			list.op = DB_LOCK_PUT;
			lockname = Tcl_GetStringFromObj(myobjv[1], NULL);
			lock = NAME_TO_LOCK(lockname);
			if (lock == NULL) {
				snprintf(msg, MSG_SIZE, "Invalid lock: %s\n",
				    lockname);
				Tcl_SetResult(interp, msg, TCL_VOLATILE);
				result = TCL_ERROR;
				goto error;
			}
			list.lock = *lock;
			break;
		case LKPUTALL:
			if (myobjc != 1) {
				Tcl_WrongNumArgs(interp, 1, myobjv,
				    "{put_all}");
				result = TCL_ERROR;
				goto error;
			}
			list.op = DB_LOCK_PUT_ALL;
			break;
		case LKPUTOBJ:
			if (myobjc != 2) {
				Tcl_WrongNumArgs(interp, 1, myobjv,
				    "{put_obj obj}");
				result = TCL_ERROR;
				goto error;
			}
			list.op = DB_LOCK_PUT_OBJ;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
564 565 566 567 568 569 570 571
			ret = _CopyObjBytes(interp, myobjv[1], &otmp,
			    &obj.size, &freeobj);
			if (ret != 0) {
				result = _ReturnSetup(interp, ret,
				    DB_RETOK_STD(ret), "lock vec");
				return (result);
			}
			obj.data = otmp;
572 573
			list.obj = &obj;
			break;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
574 575 576 577
		case LKTIMEOUT:
			list.op = DB_LOCK_TIMEOUT;
			break;

578 579 580 581 582 583
		}
		/*
		 * We get here, we have set up our request, now call
		 * lock_vec.
		 */
		_debug_check();
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
584
		ret = envp->lock_vec(envp, lockid, flag, &list, 1, NULL);
585 586 587 588 589 590 591
		/*
		 * Now deal with whether or not the operation succeeded.
		 * Get's were done above, all these are only puts.
		 */
		thisop = Tcl_NewIntObj(ret);
		result = Tcl_ListObjAppendElement(interp, res, thisop);
		if (ret != 0 && result == TCL_OK)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
592 593 594 595 596 597
			result = _ReturnSetup(interp, ret,
			    DB_RETOK_STD(ret), "lock put");
		if (freeobj) {
			(void)__os_free(envp, otmp);
			freeobj = 0;
		}
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
		/*
		 * We did a put of some kind.  Since we did that,
		 * we have to delete the commands associated with
		 * any of the locks we just put.
		 */
		_LockPutInfo(interp, list.op, lock, lockid, &obj);
	}

	if (result == TCL_OK && res)
		Tcl_SetObjResult(interp, res);
error:
	return (result);
}

static int
_LockMode(interp, obj, mode)
	Tcl_Interp *interp;
	Tcl_Obj *obj;
	db_lockmode_t *mode;
{
	int optindex;

	if (Tcl_GetIndexFromObj(interp, obj, lkmode, "option",
	    TCL_EXACT, &optindex) != TCL_OK)
		return (IS_HELP(obj));
	switch ((enum lkmode)optindex) {
	case LK_NG:
		*mode = DB_LOCK_NG;
		break;
	case LK_READ:
		*mode = DB_LOCK_READ;
		break;
	case LK_WRITE:
		*mode = DB_LOCK_WRITE;
		break;
	case LK_IREAD:
		*mode = DB_LOCK_IREAD;
		break;
	case LK_IWRITE:
		*mode = DB_LOCK_IWRITE;
		break;
	case LK_IWR:
		*mode = DB_LOCK_IWR;
		break;
	}
	return (TCL_OK);
}

static void
_LockPutInfo(interp, op, lock, lockid, objp)
	Tcl_Interp *interp;
	db_lockop_t op;
	DB_LOCK *lock;
	u_int32_t lockid;
	DBT *objp;
{
	DBTCL_INFO *p, *nextp;
	int found;

	for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
		found = 0;
		nextp = LIST_NEXT(p, entries);
		if ((op == DB_LOCK_PUT && (p->i_lock == lock)) ||
		    (op == DB_LOCK_PUT_ALL && p->i_locker == lockid) ||
		    (op == DB_LOCK_PUT_OBJ && p->i_lockobj.data &&
			memcmp(p->i_lockobj.data, objp->data, objp->size) == 0))
			found = 1;
		if (found) {
			(void)Tcl_DeleteCommand(interp, p->i_name);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
667
			__os_free(NULL, p->i_lock);
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
			_DeleteInfo(p);
		}
	}
}

static int
_GetThisLock(interp, envp, lockid, flag, objp, mode, newname)
	Tcl_Interp *interp;		/* Interpreter */
	DB_ENV *envp;			/* Env handle */
	u_int32_t lockid;		/* Locker ID */
	u_int32_t flag;			/* Lock flag */
	DBT *objp;			/* Object to lock */
	db_lockmode_t mode;		/* Lock mode */
	char *newname;			/* New command name */
{
	DB_LOCK *lock;
	DBTCL_INFO *envip, *ip;
	int result, ret;

	result = TCL_OK;
	envip = _PtrToInfo((void *)envp);
	if (envip == NULL) {
		Tcl_SetResult(interp, "Could not find env info\n", TCL_STATIC);
		return (TCL_ERROR);
	}
	snprintf(newname, MSG_SIZE, "%s.lock%d",
	    envip->i_name, envip->i_envlockid);
	ip = _NewInfo(interp, NULL, newname, I_LOCK);
	if (ip == NULL) {
		Tcl_SetResult(interp, "Could not set up info",
		    TCL_STATIC);
		return (TCL_ERROR);
	}
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
701
	ret = __os_malloc(envp, sizeof(DB_LOCK), &lock);
702 703 704 705 706
	if (ret != 0) {
		Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
		return (TCL_ERROR);
	}
	_debug_check();
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
707 708
	ret = envp->lock_get(envp, lockid, flag, objp, mode, lock);
	result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock get");
709
	if (result == TCL_ERROR) {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
710
		__os_free(envp, lock);
711 712 713 714 715 716 717
		_DeleteInfo(ip);
		return (result);
	}
	/*
	 * Success.  Set up return.  Set up new info
	 * and command widget for this lock.
	 */
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
718
	ret = __os_malloc(envp, objp->size, &ip->i_lockobj.data);
719 720 721
	if (ret != 0) {
		Tcl_SetResult(interp, "Could not duplicate obj",
		    TCL_STATIC);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
722 723
		(void)envp->lock_put(envp, lock);
		__os_free(envp, lock);
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
		_DeleteInfo(ip);
		result = TCL_ERROR;
		goto error;
	}
	memcpy(ip->i_lockobj.data, objp->data, objp->size);
	ip->i_lockobj.size = objp->size;
	envip->i_envlockid++;
	ip->i_parent = envip;
	ip->i_locker = lockid;
	_SetInfoData(ip, lock);
	Tcl_CreateObjCommand(interp, newname,
	    (Tcl_ObjCmdProc *)lock_Cmd, (ClientData)lock, NULL);
error:
	return (result);
}
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
739
#endif