head	1.11;
access;
symbols;
locks; strict;
comment	@ * @;


1.11
date	91.08.29.23.52.03;	author mer;	state Exp;
branches;
next	1.10;

1.10
date	91.08.14.11.27.22;	author kemnitz;	state Exp;
branches;
next	1.9;

1.9
date	91.08.12.15.16.44;	author mer;	state Exp;
branches;
next	1.8;

1.8
date	91.08.03.01.00.42;	author mer;	state Exp;
branches;
next	1.7;

1.7
date	91.08.01.14.44.50;	author mer;	state Exp;
branches;
next	1.6;

1.6
date	91.07.31.21.02.53;	author mer;	state Exp;
branches;
next	1.5;

1.5
date	91.07.29.07.21.58;	author mer;	state Exp;
branches;
next	1.4;

1.4
date	91.07.22.16.27.18;	author mer;	state Exp;
branches;
next	1.3;

1.3
date	91.07.22.15.21.32;	author mer;	state Exp;
branches;
next	1.2;

1.2
date	91.07.22.14.22.55;	author mer;	state Exp;
branches;
next	1.1;

1.1
date	91.07.15.10.40.58;	author mer;	state Exp;
branches;
next	;


desc
@new lock manager initial checkin
@


1.11
log
@purge old lmgr code
@
text
@/*
 * multi.c  -- multi level lock table manager
 *
 *  Standard multi-level lock manager as per the Gray paper
 * (at least, that is what it is supposed to be).  We implement
 * three levels -- RELN, PAGE, TUPLE.  Tuple is actually TID
 * a physical record pointer.  It isn't an object id.
 *
 * NOTES:
 *   (1) The lock.c module assumes that the caller here is doing
 * two phase locking.
 *
 *
 * Interface:
 *	MultiLockReln(), MultiLockTuple(), InitMultiLockm();
 *
 *
 * $Header: /users/mer/postgres/src/storage/lmgr/RCS/multi.c,v 1.10 1991/08/14 11:27:22 kemnitz Exp mer $
 */
#include <stdio.h>
#include "storage/lmgr.h"
#include "storage/multilev.h"

#include "utils/rel.h"
#include "utils/log.h"
#include "tmp/miscadmin.h"		/* MyDatabaseId */


/*
 * INTENT indicates to higher level that a lower level lock has been
 * set.  For example, a write lock on a tuple conflicts with a write 
 * lock on a relation.  This conflict is detected as a WRITE_INTENT/
 * WRITE conflict between the tuple's intent lock and the relation's
 * write lock.
 */
static
int MultiConflicts[] = {
  NULL,	
  /* All reads and writes at any level conflict with a write lock */
  (1 << WRITE_LOCK)|(1 << WRITE_INTENT)|(1 << READ_LOCK)|(1 << READ_INTENT),
  /* read locks conflict with write locks at curr and lower levels */
  (1 << WRITE_LOCK)| (1 << WRITE_INTENT),  
  /* write intent locks */
  (1 << READ_LOCK) | (1 << WRITE_LOCK),
  /* read intent locks*/
  (1 << WRITE_LOCK),
  /* extend locks for archive storage manager conflict only w/extend locks */
  (1 << EXTEND_LOCK)
};

/*
 * write locks have higher priority than read locks and extend locks.  May
 * want to treat INTENT locks differently.
 */
static
int MultiPrios[] = {
  NULL,
  2,
  1,
  2,
  1,
  1
};

/* 
 * Lock table identifier for this lock table.  The multi-level
 * lock table is ONE lock table, not three.
 */
LockTableId MultiTableId = NULL;
LockTableId ShortTermTableId = NULL;

/*
 * Create the lock table described by MultiConflicts and Multiprio.
 */

LockTableId
InitMultiLevelLockm()
{
  int tableId;

  /* -----------------------
   * If we're already initialized just return the table id.
   * -----------------------
   */
  if (MultiTableId)
	return MultiTableId;

  tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 5);
  MultiTableId = tableId;
  if (! (MultiTableId)) {
    elog(WARN,"InitMultiLockm: couldnt initialize lock table");
  }
  /* -----------------------
   * No short term lock table for now.  -Jeff 15 July 1991
   * 
   * ShortTermTableId = LockTabRename(tableId);
   * if (! (ShortTermTableId)) {
   *   elog(WARN,"InitMultiLockm: couldnt rename lock table");
   * }
   * -----------------------
   */
  return MultiTableId;
}

/*
 * MultiLockReln -- lock a relation
 *
 * Returns: TRUE if the lock can be set, FALSE otherwise.
 */
bool
MultiLockReln(linfo, lockt)
LockInfo	linfo;
LOCKT		lockt;
{
  LOCKTAG	tag;

  /* LOCKTAG has two bytes of padding, unfortunately.  The
   * hash function will return miss if the padding bytes aren't
   * zero'd.
   */
  bzero(&tag,sizeof(tag));
  tag.relId = linfo->lRelId.relId;
  tag.dbId = linfo->lRelId.dbId;
  return(MultiAcquire(MultiTableId, &tag, lockt, RELN_LEVEL));
}

/*
 * MultiLockTuple -- Lock the TID associated with a tuple
 *
 * Returns: TRUE if lock is set, FALSE otherwise.
 *
 * Side Effects: causes intention level locks to be set
 * 	at the page and relation level.
 */
bool
MultiLockTuple(linfo, tidPtr, lockt)
LockInfo	linfo;
ItemPointer	tidPtr;
LOCKT		lockt;		
{
  LOCKTAG	tag;

  /* LOCKTAG has two bytes of padding, unfortunately.  The
   * hash function will return miss if the padding bytes aren't
   * zero'd.
   */
  bzero(&tag,sizeof(tag));

  tag.relId = linfo->lRelId.relId;
  tag.dbId = linfo->lRelId.dbId;

  /* not locking any valid Tuple, just the page */
  tag.tupleId = *tidPtr;
  return(MultiAcquire(MultiTableId, &tag, lockt, TUPLE_LEVEL));
}

/*
 * same as above at page level
 */
bool
MultiLockPage(linfo, tidPtr, lockt)
LockInfo	linfo;
ItemPointer	tidPtr;
LOCKT		lockt;		
{
  LOCKTAG	tag;

  /* LOCKTAG has two bytes of padding, unfortunately.  The
   * hash function will return miss if the padding bytes aren't
   * zero'd.
   */
  bzero(&tag,sizeof(tag));


  /* ----------------------------
   * Now we want to set the page offset to be invalid 
   * and lock the block.  There is some confusion here as to what
   * a page is.  In Postgres a page is an 8k block, however this
   * block may be partitioned into many subpages which are sometimes
   * also called pages.  The term is overloaded, so don't be fooled
   * when we say lock the page we mean the 8k block. -Jeff 16 July 1991
   * ----------------------------
   */
  tag.relId = linfo->lRelId.relId;
  tag.dbId = linfo->lRelId.dbId;
  BlockIdCopy( ItemPointerBlockId(&tag.tupleId), ItemPointerBlockId(tidPtr) );
  return(MultiAcquire(MultiTableId, &tag, lockt, PAGE_LEVEL));
}

/*
 * MultiAcquire -- acquire multi level lock at requested level
 *
 * Returns: TRUE if lock is set, FALSE if not
 * Side Effects:
 */
bool
MultiAcquire(tableId, tag, lockt, level)
LockTableId		tableId;
LOCKTAG		*tag;
LOCK_LEVEL  	level;
LOCKT		lockt;
{
  LOCKT locks[N_LEVELS];
  int	i,status;
  LOCKTAG 	xxTag, *tmpTag = &xxTag;
  int	retStatus = TRUE;

  /*
   * Three levels implemented.  If we set a low level (e.g. Tuple)
   * lock, we must set INTENT locks on the higher levels.  The 
   * intent lock detects conflicts between the low level lock
   * and an existing high level lock.  For example, setting a
   * write lock on a tuple in a relation is disallowed if there
   * is an existing read lock on the entire relation.  The
   * write lock would set a WRITE + INTENT lock on the relation
   * and that lock would conflict with the read.
   */
  switch (level) {
  case RELN_LEVEL:
    locks[0] = lockt;
    locks[1] = NO_LOCK;
    locks[2] = NO_LOCK;
    break;
  case PAGE_LEVEL:
    locks[0] = lockt + INTENT;
    locks[1] = lockt;
    locks[2] = NO_LOCK;
    break;
  case TUPLE_LEVEL:
    locks[0] = lockt + INTENT;
    locks[1] = lockt + INTENT;
    locks[2] = lockt;
    break;
  default:
    elog(WARN,"MultiAcquire: bad lock level");
    return(FALSE);
  }
  
  /*
   * construct a new tag as we go. Always loop through all levels,
   * but if we arent' seting a low level lock, locks[i] is set to
   * NO_LOCK for the lower levels.  Always start from the highest
   * level and go to the lowest level. 
   */
  bzero(tmpTag,sizeof(*tmpTag));
  tmpTag->relId = tag->relId;
  tmpTag->dbId = tag->dbId;

  for (i=0;i<N_LEVELS;i++) {
    if (locks[i] != NO_LOCK) {
      switch (i) {
      case RELN_LEVEL:
	/* -------------
	 * Set the block # and offset to invalid
	 * -------------
	 */
	BlockIdSet(ItemPointerBlockId(&tmpTag->tupleId), InvalidBlockNumber);
	PositionIdSetInvalid( ItemPointerPositionId(&(tmpTag->tupleId)) );
	break;
      case PAGE_LEVEL:
	/* -------------
	 * Copy the block #, set the offset to invalid
	 * -------------
	 */
	BlockIdCopy(ItemPointerBlockId(&tmpTag->tupleId),ItemPointerBlockId(&tag->tupleId));

	PositionIdSetInvalid(ItemPointerPositionId(&(tmpTag->tupleId)));
	break;
      case TUPLE_LEVEL:
	/* --------------
	 * Copy the entire tuple id.
	 * --------------
	 */
	ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
	break;
      }

      status = LockAcquire(tableId, tmpTag, locks[i]);
      if (! status) {
	/* failed for some reason. Before returning we have
	 * to release all of the locks we just acquired.
	 * MultiRelease(xx,xx,xx, i) means release starting from
	 * the last level lock we successfully acquired
	 */
	retStatus = FALSE;
	(void) MultiRelease(tableId, tag, lockt, i);
	/* now leave the loop.  Don't try for any more locks */
	break;
      }
    }
  }
  return(retStatus);
}

/* ------------------
 * Release a page in the multi-level lock table
 * ------------------
 */
bool
MultiReleasePage(linfo, tidPtr, lockt)
LockInfo	linfo;
ItemPointer	tidPtr;
LOCKT		lockt;		
{
  LOCKTAG tag;

  /* ------------------
   * LOCKTAG has two bytes of padding, unfortunately.  The
   * hash function will return miss if the padding bytes aren't
   * zero'd.
   * ------------------
   */
  bzero(&tag, sizeof(LOCKTAG));

  tag.relId = linfo->lRelId.relId;
  tag.dbId = linfo->lRelId.dbId;
  BlockIdCopy( ItemPointerBlockId(&tag.tupleId), ItemPointerBlockId(tidPtr) );

  return (MultiRelease(MultiTableId, &tag, lockt, PAGE_LEVEL));
}

/* ------------------
 * Release a relation in the multi-level lock table
 * ------------------
 */
bool
MultiReleaseReln(linfo, lockt)
LockInfo	linfo;
LOCKT		lockt;		
{
  LOCKTAG tag;

  /* ------------------
   * LOCKTAG has two bytes of padding, unfortunately.  The
   * hash function will return miss if the padding bytes aren't
   * zero'd.
   * ------------------
   */
  bzero(&tag, sizeof(LOCKTAG));
  tag.relId = linfo->lRelId.relId;
  tag.dbId = linfo->lRelId.dbId;

  return (MultiRelease(MultiTableId, &tag, lockt, RELN_LEVEL));
}

/*
 * MultiRelease -- release a multi-level lock
 *
 * Returns: TRUE if successful, FALSE otherwise.
 */
bool
MultiRelease(tableId, tag, lockt, level)
LockTableId		tableId;
LOCKTAG		*tag;
LOCK_LEVEL  	level;
LOCKT		lockt;
{
  LOCKT 	locks[N_LEVELS];
  int		i,status;
  LOCKTAG 	xxTag, *tmpTag = &xxTag;

  /* 
   * same level scheme as MultiAcquire().
   */
  switch (level) {
  case RELN_LEVEL:
    locks[0] = lockt;
    locks[1] = NO_LOCK;
    locks[2] = NO_LOCK;
    break;
  case PAGE_LEVEL:
    locks[0] = lockt + INTENT;
    locks[1] = lockt;
    locks[2] = NO_LOCK;
    break;
  case TUPLE_LEVEL:
    locks[0] = lockt + INTENT;
    locks[1] = lockt + INTENT;
    locks[2] = lockt;
    break;
  default:
    elog(WARN,"MultiRelease: bad lockt");
  }
  
  /*
   * again, construct the tag on the fly.  This time, however,
   * we release the locks in the REVERSE order -- from lowest
   * level to highest level.  
   *
   * Must zero out the tag to set padding byes to zero and ensure
   * hashing consistency.
   */
  bzero(tmpTag,sizeof(*tmpTag));
  tmpTag->relId = tag->relId;
  tmpTag->dbId =  tag->dbId;

  for (i=(N_LEVELS-1); i>=0; i--) 
  {
    if (locks[i] != NO_LOCK) 
    {
      switch (i) 
      {
      case RELN_LEVEL:
        /* -------------
         * Set the block # and offset to invalid
         * -------------
         */
        BlockIdSet(ItemPointerBlockId(&tmpTag->tupleId),InvalidBlockNumber);
        PositionIdSetInvalid(ItemPointerPositionId(&tmpTag->tupleId));
        break;
      case PAGE_LEVEL:
        /* -------------
         * Copy the block #, set the offset to invalid
         * These long macros cannot have newlines in them or else... 8-X
         * -------------
         */
        BlockIdCopy(ItemPointerBlockId(&tmpTag->tupleId),ItemPointerBlockId(&tag->tupleId));
  
        PositionIdSetInvalid(ItemPointerPositionId(&(tmpTag->tupleId)));
        break;
      case TUPLE_LEVEL:
        ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
        break;
      }
      status = LockRelease(tableId, tmpTag, locks[i]);
      if (! status) {
	elog(WARN,"MultiRelease: couldn't release after error");
      }
    }
  }
}
@


1.10
log
@fixed Sparc compile error.
@
text
@d18 1
a18 1
 * $Header: RCS/multi.c,v 1.9 91/08/12 15:16:44 mer Exp Locker: kemnitz $
d21 1
d23 1
a23 2
#include "storage/lock.h"
#include "storage/lmgr.h"
d69 2
a70 2
TableId MultiTableId = NULL;
TableId ShortTermTableId = NULL;
d76 1
a76 1
TableId
d110 1
d135 1
d160 1
d196 1
d198 1
a198 1
TableId		tableId;
d299 1
d326 1
d351 1
d353 1
a353 1
TableId		tableId;
@


1.9
log
@multi-user fixes and functionality additions
@
text
@d18 1
a18 1
 * $Header: /users/mer/postgres/src/storage/lmgr/RCS/multi.c,v 1.8 91/08/03 01:00:42 mer Exp Locker: mer $
d23 1
a23 1
#include "storage/lmgr.h
@


1.8
log
@add extend locks
@
text
@d5 1
a5 1
 * (at least, that is what it is supposed to be).  I implement
d7 1
a7 3
 * a physical record pointer.  It isn't an object id.  I need
 * that in order to reserve space for a  TupleInsert() and,
 * hopefully, it is what the rest of POSTGRES needs as well.
a16 2
 * MultiLockRelease() is not currently used but will be when we
 * implement short term locking.
d18 1
a18 1
 * $Header: RCS/multi.c,v 1.7 91/08/01 14:44:50 mer Exp Locker: mer $
d20 2
a21 1
#include "storage/shmem.h"
d23 1
a26 1
#include "storage/multilev.h"
d110 2
a111 2
MultiLockReln(reln, lockt)
Relation *	reln;
d121 2
a122 2
  tag.relId = RelationGetRelationId(reln);
  tag.dbId = MyDatabaseId;
d134 2
a135 2
MultiLockTuple(reln, tidPtr, lockt)
Relation *	reln;
d147 2
a148 2
  tag.relId = RelationGetRelationId(reln);
  tag.dbId = MyDatabaseId;
d158 2
a159 2
MultiLockPage(reln, tidPtr, lockt)
Relation	*reln;
d181 2
a182 2
  tag.relId = RelationGetRelationId(reln);
  tag.dbId = MyDatabaseId;
d295 2
a296 2
MultiReleasePage(reln, tidPtr, lockt)
Relation	*reln;
d310 2
a311 2
  tag.relId = RelationGetRelationId(reln);
  tag.dbId = MyDatabaseId;
d321 2
a322 2
MultiReleaseReln(reln, lockt)
Relation	*reln;
d334 2
a335 2
  tag.relId = RelationGetRelationId(reln);
  tag.dbId = MyDatabaseId;
@


1.7
log
@add backendId and dbId to hash table tags
@
text
@d22 1
a22 1
 * $Header: /users/mer/postgres/src/storage/lmgr/RCS/multi.c,v 1.6 91/07/31 21:02:53 mer Exp Locker: mer $
d42 2
a43 2
  /* everything conflicts with a write lock */
  0xF,  
d50 2
a51 1
  /* Will add extend locks for archive storage manager */
d55 1
a55 1
 * write locks have higher priority than read locks.  May
d64 1
d91 1
a91 1
  tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 4);
@


1.6
log
@release locks + bug fixes
@
text
@d22 1
a22 1
 * $Header: RCS/multi.c,v 1.5 91/07/29 07:21:58 mer Exp Locker: mer $
d28 1
d123 1
d149 1
d183 1
d244 1
d312 1
d336 1
d389 2
@


1.5
log
@new macro city
@
text
@d22 1
a22 1
 * $Header: /users/mer/postgres/src/storage/lmgr/RCS/multi.c,v 1.4 91/07/22 16:27:18 mer Exp Locker: mer $
d287 10
d298 36
d376 3
d380 1
d382 29
a410 28
  for (i=N_LEVELS;i;i--) {
    switch (i) {
    case RELN_LEVEL:
      /* -------------
       * Set the block # and offset to invalid
       * -------------
       */
      BlockIdSet(ItemPointerBlockId(&tmpTag->tupleId),InvalidBlockNumber);
      PositionIdSetInvalid(ItemPointerPositionId(&tmpTag->tupleId));
      break;
    case PAGE_LEVEL:
      /* -------------
       * Copy the block #, set the offset to invalid
       * These long macros cannot have newlines in them or else... 8-0X
       * -------------
       */
      BlockIdCopy(ItemPointerBlockId(&tmpTag->tupleId),ItemPointerBlockId(&tag->tupleId));

      PositionIdSetInvalid(ItemPointerPositionId(&(tmpTag->tupleId)));
      break;
    case TUPLE_LEVEL:
      ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
      break;
    }
    if (locks[i] == NO_LOCK) {
      break;
    } else {
      status = LockRelease(tableId, tag, locks[i]);
d412 1
a412 1
	elog(WARN,"MultiAcquire: couldn't release after error");
@


1.4
log
@fix compile error
@
text
@d22 1
a22 1
 * $Header: RCS/multi.c,v 1.3 91/07/22 15:21:32 mer Exp Locker: mer $
a168 1
  tag.relId = RelationGetRelationId(reln);
d179 2
a180 2
  ItemPointerSetInvalid( &(tag.tupleId) );
  BlockIdCopy( &(tag.tupleId.blockData), &(tidPtr->blockData) );
d245 6
a250 1
	ItemPointerSetInvalid( &(tmpTag->tupleId) );
d253 7
a259 2
	ItemPointerSetInvalid( &(tmpTag->tupleId) );
	BlockIdCopy(&(tmpTag->tupleId.blockData),&tag->tupleId.blockData);
d262 4
d335 6
a340 1
      ItemPointerSetInvalid( &(tmpTag->tupleId) );
d343 8
a350 2
      ItemPointerSetInvalid( &(tmpTag->tupleId) );
      BlockIdCopy(&(tmpTag->tupleId.blockData),&tag->tupleId.blockData);
@


1.3
log
@get rid of sem.h include
@
text
@d22 1
a22 1
 * $Header: RCS/multi.c,v 1.2 91/07/22 14:22:55 mer Exp Locker: mer $
d76 1
a76 1
LockTableId
@


1.2
log
@incremental check in (not complete yet)
@
text
@d22 1
a22 1
 * $Header: RCS/multi.c,v 1.1 91/07/15 10:40:58 mer Exp Locker: mer $
a23 1
#include "storage/sem.h"
@


1.1
log
@Initial revision
@
text
@d22 1
a22 1
 * $Header$
d24 6
a29 6
#include "def.h"
#include "sem.h"
#include "shmem.h"
#include "lock.h"
#include "reln.h"
#include "multilev.h"
d39 1
a39 1
private
d50 1
d57 1
a57 1
private
d76 2
d82 8
a89 1
  tableId = LockTabInit("LockTable",MultiConflicts,MultiPrios,4);
d94 10
a103 4
  ShortTermTableId = LockTabRename(tableId);
  if (! (ShortTermTableId)) {
    elog(WARN,"InitMultiLockm: couldnt rename lock table");
  }
d112 1
a112 1
Reln *		reln;
d122 1
a122 1
  RelnGetOid(reln,&tag.relId);
d135 2
a136 2
Reln *		reln;
TupleId		*tidPtr;
d146 3
a148 1
  RelnGetOid(reln,&(tag.relId));
d158 2
a159 2
Reln *		reln;
TupleId		*tidPtr;
d169 14
a182 2
  RelnGetOid(reln,&(tag.relId));
  MAKE_TID(tag.tupleId,tidPtr->blockNum,INVALID_TID);
d237 1
a237 1
   * NO_LOCK for the lowere levels.  Always start from the highest
d241 1
a241 1
  OID_Assign(tmpTag->relId,tag->relId);
d247 1
a247 1
	MAKE_TID(tmpTag->tupleId,INVALID_TID,INVALID_TID);
d250 2
a251 1
	MAKE_TID(tmpTag->tupleId,tag->tupleId.blockNum,INVALID_TID);
d254 1
a254 1
	tmpTag->tupleId = tag->tupleId;
d319 1
a319 1
  OID_Assign(tmpTag->relId,tag->relId);
d323 1
a323 1
      MAKE_TID(tmpTag->tupleId,INVALID_TID,INVALID_TID);
d326 2
a327 1
      MAKE_TID(tmpTag->tupleId,tag->tupleId.blockNum,INVALID_TID);
d330 1
a330 1
      tmpTag->tupleId = tag->tupleId;
@
