/* This file was generated by scm2java from source file "ents.scm" */
/*  "ents.scm" WB-tree File Based Associative String Data Base System. */
/*  Copyright (C) 1991, 1992, 1993, 2000, 2003, 2006 Free Software Foundation, Inc. */
/*  */
/*  This program is free software: you can redistribute it and/or modify */
/*  it under the terms of the GNU Lesser General Public License as */
/*  published by the Free Software Foundation, either version 3 of the */
/*  License, or (at your option) any later version. */
/*  */
/*  This program is distributed in the hope that it will be useful, but */
/*  WITHOUT ANY WARRANTY; without even the implied warranty of */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/*  Lesser General Public License for more details. */
/*  */
/*  You should have received a copy of the GNU Lesser General Public */
/*  License along with this program.  If not, see */
/*  <http://www.gnu.org/licenses/>. */



package wb;

import static wb.Scan.*;
import static wb.Blkio.*;
import static wb.Prev.*;
import static wb.Stats.*;
import static wb.Blink.*;
import static wb.Segs.*;
import static wb.Handle.*;
import static wb.Wbdefs.*;
import static wb.SchlepRT.*;
import static wb.Wbsys.*;
import static wb.Blk.*;
import static wb.Pkt.*;
import static wb.Ent.*;
import static wb.Seg.*;
import static wb.Han.*;
import static wb.Lck.*;
public class Ents {

/*  tables */


public static Lck []lckTab = null;

public static Ent []bukTab = null;

public static Ent []entTab = null;

public static int numEntsCt = 0;

public static int numBuks = 0;

public static int blkSize = 0;


public static boolean cacheEntEnable_P = (true);

/*  DATABASE LEVEL OPERATIONS */

/*  This can be bummed to write less than the full BSIZ if we know */
/*  what the disk sector size is. */
/*  fixed order check in ent-write */


public static boolean ents_EntWrite(Ent ent)
{
  Seg seg = ent_Seg(ent);
  byte []blk = ent_Blk(ent);
  if (!(blk_Typ_P(blk, seqTyp)))
    checkKeyOrder(blk);
  blk_SetTime(blk, (int)(System.currentTimeMillis()/1000));
  if (!(seg_Mutable_P(seg)))
    {
      System.err.print(">>>>ERROR<<<< "+("entWrite")+" on read only segment "+(seg_Id(seg))+"?\n");
      return false;
    }
  else if (blkio_Write(seg_Port(seg), blk, seg_Bsiz(seg), ent_Id(ent)))
    {
      ent_SetDty(ent, null);
      return (true);
    }
  else {
    ent_SetDty(ent, true);
    return false;
  }
}

/*  FLUSHING needs to be proportional to time (to put some limit on */
/*  how long things are left unwritten) plus write-activity. */

/*  NOTE: While flushing a buffer, get ACCPEND accmode to it (to */
/*  prevent surprise mods) */


public static int flushEntCntr = 0;

public static Lck flushEntLck = makeLck( -2);


public static int entsFlush(int trynum,int flushnum)
{
  int flushednum = 0;
  if (a2b(flushEntLck)
      && tryLck_P(flushEntLck))
    {
      int iCt = trynum;
      while (!((0==(iCt)
	       || (flushednum)>=(flushnum)))) {
	flushEntCntr = (1+(flushEntCntr))%(numEntsCt);
	{
	  Ent tent = entTab[flushEntCntr];
	  if (ent_Dty_P(tent)
	      && !(a2b(ent_Acc(tent)))
	      && entFlush_P(tent))
	    {
	      showBuffer1(tent);
	      flushednum = (flushednum)+1;
	    }
	}
	{
	  iCt = (iCt)-1;
	}
      }
      unlck(flushEntLck);
      return flushednum;
    }
  else return 0;
}


public static boolean entFlush_P(Ent tent)
{
  Seg eSeg = ent_Seg(tent);
  int eId = ent_Id(tent);
  getBukLck_P(seg_Id(eSeg), eId);
  {
    Ent ent = getBuk(seg_Id(eSeg), eId);
Lloop: while (true) {
    if (!(a2b(ent)))
      {
	relBuk(seg_Id(eSeg), eId);
	return false;
      }
    else if ((tent)!=(ent))
      {
	ent = ent_Next(ent);
	continue Lloop;
      }
    else if (!(ent_Dty_P(ent)
	    && (accnone)==(ent_Acc(ent))))
      {
	relBuk(seg_Id(eSeg), eId);
	return false;
      }
    else {
      ent_SetAcc(ent, accpend);
      relBuk(seg_Id(eSeg), eId);
      ents_EntWrite(ent);
      getBukWait(seg_Id(eSeg), eId);
      ent_SetAcc(ent, accnone);
      relBuk(seg_Id(eSeg), eId);
      flushCt = (flushCt)+1;
      return (true);
    }
    }
  }
}

/*  release-ent! gives up all claim to ent, which is expected to be of */
/*  type accmode */
/*  fixed warning about dirty dirs -- twice */
/*  fixed dirty-block writer in UPDATE-ACCESS! */


public static void releaseEnt(Ent ent,int accmode)
{
  int blknum = ent_Id(ent);
  Seg seg = ent_Seg(ent);
  Ent buk = null;
  buk = getBukWait(seg_Id(seg), blknum);
  if ((accnone)!=(accmode)
      && (ent_Acc(ent))!=(accmode))
    System.err.print(">>>>ERROR<<<< "+("releaseEnt")+": unexpected accmode of "+(seg_Id(seg))+":"+(blknum)+" is "+(ent_Acc(ent))
   +" not "+(accmode)+"\n");
  if ((accnone)==(accmode))
    ;
  else if (!(ent_Dty_P(ent)))
    ;
  else if (blk_Typ_P(ent_Blk(ent), dirTyp)
      && leaf_P(ent_Blk(ent)))
    {
      System.err.print("WARNING: Directory block "+(seg_Id(seg))+":"+(blknum)+" dirty at RELEASE-ENT! \n");
      dirDtyCt = 1+(dirDtyCt);
    }
  else if (blk_Typ_P(ent_Blk(ent), seqTyp))
    {
      relBuk(seg_Id(seg), blknum);
      ents_EntWrite(ent);
      buk = getBukWait(seg_Id(seg), blknum);
    }
  if ((accnone)!=(accmode))
    ent_SetAcc(ent, accnone);
  if ((ent_Ref(ent))<=0)
    {
      ent_SetRef(ent, 0);
      System.err.print(">>>>ERROR<<<< REF count below 0 in "+(seg_Id(seg))+":"+(blknum)+"\n");
    }
  else ent_SetRef(ent, (ent_Ref(ent))-1);
  if (!(a2b(seg)))
    {
      spliceOutEnt(seg, blknum, buk, ent);
    }
  else ent_SetAge(ent, ((ent_Dty_P(ent)
       ?5
       :0))+(5*(6+((leaf)-(blk_Level(ent_Blk(ent)))))));
  relBuk(seg_Id(seg), blknum);
  return;
}


public static boolean ents_EntUpdateAccess_P(Ent ent,int oldAccmode,int newAccmode)
{
  getBukWait(seg_Id(ent_Seg(ent)), ent_Id(ent));
  if ((ent_Acc(ent))!=(oldAccmode))
    {
      relBuk(seg_Id(ent_Seg(ent)), ent_Id(ent));
      System.err.print(">>>>ERROR<<<< unexpected accmode type on "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+" "+(ent_Acc(ent))+" (expected "+(oldAccmode)
   +")\n");
    }
  if ((accnone)==(oldAccmode))
    ;
  else if (!(ent_Dty_P(ent)))
    ;
  else if (blk_Typ_P(ent_Blk(ent), seqTyp))
    {
      relBuk(seg_Id(ent_Seg(ent)), ent_Id(ent));
      ents_EntWrite(ent);
      getBukWait(seg_Id(ent_Seg(ent)), ent_Id(ent));
    }
  else if (blk_Typ_P(ent_Blk(ent), dirTyp)
      && leaf_P(ent_Blk(ent)))
    {
      System.err.print("WARNING: Directory block "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+" dirty at ENT-UPD-ACCESS! \n");
      dirDtyCt = 1+(dirDtyCt);
    }
  ent_SetAcc(ent, newAccmode);
  relBuk(seg_Id(ent_Seg(ent)), ent_Id(ent));
  return a2b(ent)
  && (true);
}

/*  ENT-FREE-LIST stuff ----------------------------------------------------------- */


public static int freeBukCntr = 0;

public static Ent freeEnts = null;

public static Lck freeEntLck = makeLck( -1);


public static Ent getFreeFreeEnt()
{
  lck(freeEntLck);
  if (a2b(freeEnts))
    {
      Ent freeEnt = freeEnts;
      freeEnts = ent_Next(freeEnts);
      unlck(freeEntLck);
      return freeEnt;
    }
  else return null;
}

/*  this version assumes the caller has already locked the bucket */
/*  BUK containing ENT */


public static void spliceOutEnt(Seg seg,int blkNum,Ent buk,Ent ent)
{
  {
    Ent bent = buk;
    Ent lastent = null;
    while (!((!(a2b(bent))
	     || (bent)==(ent)))) {
      {
	Ent T_bent = ent_Next(bent);
	lastent = bent;
	bent = T_bent;
      }
    }
    if (a2b(bent))
      {
	if (a2b(lastent))
	  {
	    ent_SetNext(lastent, ent_Next(bent));
	  }
	else setBuk(seg_Id(seg), blkNum, ent_Next(bent));
	recycleEnt(bent);
	return;
      }
    else System.err.print("WARNING: "+("spliceOutEnt")+" couldn't "+(seg_Id(seg))+":"+(blkNum)+"\n");
    return;
  }
}


public static void recycleEnt(Ent ent)
{
  ent_SetDty(ent, null);
  ent_SetPus(ent, 0);
  ent_SetSeg(ent, null);
  ent_SetId(ent, 0);
  lck(freeEntLck);
  ent_SetRef(ent, 0);
  ent_SetAcc(ent, accnone);
  ent_SetNext(ent, freeEnts);
  freeEnts = ent;
  unlck(freeEntLck);
  return;
}

/*  SELECT-IDLE-ENT selects a candidate entry for reuse.  caller needs to call */
/*  RECLAIM-ENT next to splice entry out of its bucket. */
/*  NOTE: when called, bucket (lseg lblk-num) is lcked. */
/*  The target bucket is assumed unlocked if lseg < 0. */
/*  (GET-ENT calls this with the bucket locked to prevent someone else from */
/*  getting another entry for the same block.) */


public static Ent selectIdleEnt(Seg lseg,int lblkNum)
{
  {
    Ent oldestEnt = null;
    int numScan = Math.max(Math.min(numBuks, 0xa), (numBuks)/0x14);
    int freeBase = freeBukCntr;
    freeBukCntr = ((numScan)+(freeBukCntr))%(numBuks);
    unlck(freeEntLck);
    {
      int i = 0;
      while (!(((i)>(numScan)
		   && a2b(oldestEnt)
	       || (i)>(numBuks)))) {
	{
	  int freeNum = ((freeBase)+(i))%(numBuks);
	  boolean dontLock_P = (!(a2b(lseg))
	    ?false
	    :(freeNum)==(hash2int(seg_Id(lseg), lblkNum)));
	  if ((dontLock_P
		  || getBukLck_P(0, freeNum)))
	    {
	      Ent ent = getBuk(0, freeNum);
	      while (a2b(ent)) {
		if (0==(ent_Ref(ent)))
		  {
		    ent_SetAge(ent, ((ent_Dty_P(ent)
			 ?1
			 :2))+(ent_Age(ent)));
		    if ((accnone)==(ent_Acc(ent))
		        && (!(a2b(oldestEnt))
			       || (ent_Age(ent))>(ent_Age(oldestEnt))))
		      oldestEnt = ent;
		  }
		{
		  ent = ent_Next(ent);
		}
	      }
	      if (dontLock_P)
		;
	      else relBuk(0, freeNum);
	    }
	}
	{
	  i = (i)+1;
	}
      }
      if ((i)>(numBuks))
	System.err.print(">>>>ERROR<<<< No free ents\n");
      return oldestEnt;
    }
  }
}

/*  RECLAIM-ENT unlinks ENT from its bucket if its not in use. */
/*  It writes out the entry-s block if it's dirty */
/*  RECLAIM-ENT has 3 cases */
/*   (a) ENT is in use -- LSEG is unlocked, NIL is returned */
/*   (b) ENT is clean -- ENT is unlinked and returned */
/*   (c) ENT is DIRTY -- ENT is written, unlinked, and reclaimed (put on */
/*             free lsit); LSEG is UNLOCKED, NIL is returned. */
/*     possible optimization in case (c): if LSEG = -, */
/*     ENT could be written, unlinked, and returned (like (b)) */


public static Ent reclaimEnt(Ent ent,Seg lseg,int lblkNum)
{
  {
    Seg seg = ent_Seg(ent);
    int blkNum = ent_Id(ent);
    boolean segsEqual_P = a2b(lseg)
    && sameBuk_P(seg_Id(lseg), lblkNum, seg_Id(seg), blkNum);
    Ent buk = (segsEqual_P
      ?getBuk(seg_Id(seg), blkNum)
      :getBukWait(seg_Id(seg), blkNum));
    if ((!(0==(ent_Ref(ent)))
        || (accnone)!=(ent_Acc(ent))))
      {
	relBuk(seg_Id(seg), blkNum);
	if (segsEqual_P)
	  ;
	else if (!(a2b(lseg)))
	  ;
	else relBuk(seg_Id(lseg), lblkNum);
	System.err.print("WARNING: "+("reclaimEnt")+": couldn't splice-out-ent "+(seg_Id(lseg))+":"+(lblkNum)+"\n");
	return null;
      }
    else {
      Ent bent = buk;
      Ent lastent = null;
      while (!((!(a2b(bent))
	       || (ent)==(bent)))) {
	{
	  Ent T_bent = ent_Next(bent);
	  lastent = bent;
	  bent = T_bent;
	}
      }
      if (!(a2b(bent)))
	{
	  relBuk(seg_Id(seg), blkNum);
	  if (segsEqual_P)
	    ;
	  else if (!(a2b(lseg)))
	    ;
	  else relBuk(seg_Id(lseg), lblkNum);
	  System.err.print(">>>>ERROR<<<< "+("reclaimEnt")+": couldn't find ent in bucket "+(seg_Id(seg))+":"+(blkNum)+" l="+(seg_Id(lseg))
   +":"+(lblkNum)+"\n");
	  return null;
	}
      else if (!(ent_Dty_P(ent)))
	{
	  if (a2b(lastent))
	    {
	      ent_SetNext(lastent, ent_Next(ent));
	    }
	  else setBuk(seg_Id(seg), blkNum, ent_Next(ent));
	  ent_SetNext(ent, null);
	  if (segsEqual_P)
	    ;
	  else relBuk(seg_Id(seg), blkNum);
	  return ent;
	}
      else {
	ent_SetAcc(ent, accpend);
	relBuk(seg_Id(seg), blkNum);
	if (segsEqual_P)
	  ;
	else if (!(a2b(lseg)))
	  ;
	else relBuk(seg_Id(lseg), lblkNum);
	ents_EntWrite(ent);
	buk = getBukWait(seg_Id(seg), blkNum);
	ent_SetAcc(ent, accnone);
	spliceOutEnt(seg, blkNum, buk, ent);
	relBuk(seg_Id(seg), blkNum);
	return null;
      }
    }
  }
}

/*  TRY-GET-FREE-ENT either returns a free ent OR unlocks (lseg lblk-num) */


public static Ent tryGetFreeEnt(Seg lseg,int lblkNum)
{
  Ent ent = getFreeFreeEnt();
  if (!(a2b(ent)))
    {
      ent = selectIdleEnt(lseg, lblkNum);
      if (a2b(ent))
	{
	  ent = reclaimEnt(ent, lseg, lblkNum);
	}
      else if (!(a2b(lseg)))
	;
      else relBuk(seg_Id(lseg), lblkNum);
    }
  return ent;
}


/*  Special entry points for Jonathan to do non-B-tree stuff. */
/*  Also now used in chain-scan. */


public static Ent allocateEnt()
{
  {
    Ent ent = tryGetFreeEnt(null,  -1);
    int cnt = 0x13;
Lloop: while (true) {
    if (a2b(ent))
      {
	ent_SetAcc(ent, accwrite);
	ent_SetDty(ent, true);
	ent_SetPus(ent, 0);
	ent_SetSeg(ent, null);
	ent_SetId(ent, 0);
	ent_SetRef(ent, 1);
	ent_SetNext(ent, null);
	return ent;
      }
    else if (0==(cnt))
      return null;
    else {
      ent = tryGetFreeEnt(null,  -1);
      cnt =  -1+(cnt);
      continue Lloop;
    }
    }
  }
}


public static void entCopy(Ent toEnt,Ent fromEnt)
{
  if ((ent_Acc(toEnt))!=(accwrite))
    System.err.print(">>>>ERROR<<<< "+("entCopy")+": copying into non-ACCWRITE "+(seg_Id(ent_Seg(toEnt)))+":"+(ent_Id(toEnt))+"\n");
  ent_SetSeg(toEnt, ent_Seg(fromEnt));
  ent_SetId(toEnt, ent_Id(fromEnt));
  subbytesMove(ent_Blk(fromEnt), 0, seg_Bsiz(ent_Seg(fromEnt)), ent_Blk(toEnt), 0);
  return;
}


public static boolean getEntCopy(Ent toEnt,Seg seg,int blkNum)
{
  Ent fromEnt = getEnt(seg, blkNum, accread);
  if (a2b(fromEnt))
    {
      entCopy(toEnt, fromEnt);
      releaseEnt(fromEnt, accread);
      return (true);
    }
  else return false;
}


public static void flushFlc(Seg seg,int fullness)
{
LflushFlc:while (true) {
  {
    byte []fstr = new byte[4];
    byte []tstr = new byte[4];
    lck(seg_Lck(seg));
    if ((seg_FlcLen(seg))<=(fullness))
      {
	unlck(seg_Lck(seg));
	return;
      }
    else if ((true))
      {
	long2str(fstr, 0, seg_Flc(seg)[(seg_FlcLen(seg))-1]);
	seg_SetFlcLen(seg, (seg_FlcLen(seg))-1);
	unlck(seg_Lck(seg));
	long2str(tstr, 0, (int)(System.currentTimeMillis()/1000));
	btPut(seg_FlHan(seg), fstr, 4, tstr, 4);
	continue LflushFlc;
      }
  }
  return;
}
}

/*  Assumes that SEG-LCK is locked by this process */


public static boolean initloadFlc_P(Seg seg)
{
  switch (seg_FlcLen(seg)) {
  case  -1:
    {
      byte []tmpStr = new byte[0x14];
      int flcImageLen = btGet(seg_RtHan(seg), flcByts, 3, tmpStr);
      if (0 > (flcImageLen))
	flcImageLen = 0;
      btPut(seg_RtHan(seg), flcByts, 3, noByts, 0);
      seg_SetFlcLen(seg, (flcImageLen)/4);
      {
	int i =  -4+(flcImageLen);
	while (!(0 > (i))) {
	  seg_Flc(seg)[(i)/4] = str2long(tmpStr, i);
	  {
	    i =  -4+(i);
	  }
	}
      }
    }
    return (true);
  case  -2:
    System.err.print(">>>>ERROR<<<< "+("initloadFlc")+" on read only segment "+(seg_Id(seg))+"?\n");
    return false;
  default:
    return (true);
  }
}

/*  Called with SEG-LCK locked. */
/*  If you don't know what you are doing. DON'T DO IT! */
/*  Compute inverse hash function so that ent can still be found. */

public static void amnesiaEnt(Ent ent)
{
  int segid = seg_Id(ent_Seg(ent));
  {
    int hash = hash2int(segid, ent_Id(ent));
    int newid = hash2int(1+(segid), ent_Id(ent));
    ent_SetId(ent, newid);
    ent_SetSeg(ent, null);
    if ((hash)!=(hash2int( -1, newid)))
      System.err.print("WARNING: "+("amnesiaEnt")+": hash mismatch "+(hash)+" >< "+(hash2int( -1, newid))+"\n");
    ent_SetDty(ent, null);
    ent_SetPus(ent, 0);
    if (a2b(ent_Blk(ent)))
      if (blk_Typ_P(ent_Blk(ent), dirTyp))
	blk_SetTyp(ent_Blk(ent), indTyp);
    ent_SetAge(ent, 0x80);
    return;
  }
}


public static boolean blkFree(Ent ent)
{
LblkFree:while (true) {
  {
    Seg seg = ent_Seg(ent);
    if ((ent_Acc(ent))!=(accwrite))
      {
	System.err.print(">>>>ERROR<<<< "+("blkFree")+": "+(seg_Id(seg))+":"+(ent_Id(ent))+" without ACCWRITE\n");
	return false;
      }
    else {
      lck(seg_Lck(seg));
      if (!(initloadFlc_P(seg)))
	{
	  unlck(seg_Lck(seg));
	  return false;
	}
      else if ((seg_FlcLen(seg))>=((flcLen)-1))
	{
	  unlck(seg_Lck(seg));
	  flushFlc(seg, (flcLen)-2);
	  continue LblkFree;
	}
      else {
	seg_Flc(seg)[seg_FlcLen(seg)] = ent_Id(ent);
	seg_SetFlcLen(seg, (seg_FlcLen(seg))+1);
	amnesiaEnt(ent);
	unlck(seg_Lck(seg));
	return (true);
      }
    }
  }
}
}


public static int flcFill(Seg seg)
{
  byte []fstr = new byte[4];
  int flen = 0;
  int status;
BunlckAndReturn:while (true) {
    lck(seg_Lck(seg));
    if ((seg_FlcLen(seg))>=1)
      {
	unlck(seg_Lck(seg));
	return success;
      }
    else if (!(tryLck_P(seg_Fck(seg))))
      {
	unlck(seg_Lck(seg));
	System.err.print("WARNING: "+("flcFill")+" failed -- branch never tried before! Segment "+(seg_Id(seg))+" "+(seg_Str(seg))+"\n");
	return retryerr;
      }
    else 
    flen = btNext(seg_FlHan(seg), noByts, 0, fstr);
    if (err_P(flen))
      {
	int xnum = (seg_Used(seg))+((flcLen)/2);
	if (blkio_FileExtend(seg_Port(seg), seg_Bsiz(seg), xnum))
	  {
	    {
	      int i = 0;
	      while (!((i)>((flcLen)/2))) {
		seg_Flc(seg)[seg_FlcLen(seg)] = (xnum)-(i);
		seg_SetFlcLen(seg, (seg_FlcLen(seg))+1);
		seg_SetUsed(seg, (seg_Used(seg))+1);
		{
		  i = (i)+1;
		}
	      }
	    }
	    {
	      byte []usedStr = new byte[4];
	      long2str(usedStr, 0, seg_Used(seg));
	      btPut(seg_RtHan(seg), usedByts, 4, usedStr, 4);
	    }
	    {
	      status = success;
	      break BunlckAndReturn;
	    }
	  }
	else {
	  System.err.print(">>>>ERROR<<<< No more file space available! Segment "+(seg_Id(seg))+" "+(seg_Str(seg))+"\n");
	  {
	    status = noroom;
	    break BunlckAndReturn;
	  }
	}
      }
    else {
      unlck(seg_Lck(seg));
      {
	int []longAra = new int[(flcLen)+1];
	byte []xstr = new byte[0x100];
	int []respkt = new int[pktSize];
	int result = success;
	subbytesMove(fstr, 0, flen, xstr, 0);
	longAra[0] = 0;
	pkt_SetSkeyCount(respkt, 0);
	result = btScan(seg_FlHan(seg), remScan, xstr, flen, noByts, endOfChain, getMethod("wb.Ents", "flcProc", new Class[]{byte[].class, int.class, byte[].class, int.class, int[].class}), longAra, respkt, 1);
	if (((result)==(success)
	    || (result)==(notpres)
	    || (result)==(terminated)))
	  {
	    lck(seg_Lck(seg));
	    {
	      int i = longAra[0];
	      while (!((i)<=0)) {
		seg_Flc(seg)[seg_FlcLen(seg)] = longAra[i];
		seg_SetFlcLen(seg, (seg_FlcLen(seg))+1);
		{
		  i = (i)-1;
		}
	      }
	    }
	    {
	      status = success;
	      break BunlckAndReturn;
	    }
	  }
	else {
	  unlck(seg_Fck(seg));
	  return result;
	}
      }
    }
  }
  unlck(seg_Lck(seg));
  unlck(seg_Fck(seg));
  return status;
}


public static int flcProc(byte []keystr,int klen,byte []vstr,int vlen,int []longAra)
{
  {
    int ct = longAra[0];
    if ((ct)<((flcLen)/2))
      {
	int num = str2long(keystr, 0);
	ct = (ct)+1;
	longAra[0] = ct;
	longAra[ct] = num;
	return success;
      }
    else return terminated;
  }
}

/*  create-new-blk-ent leaves you with ACCWRITE accmode to blk */

public static Ent createNewBlkEnt(Seg seg)
{
LcreateNewBlkEnt:while (true) {
  lck(seg_Lck(seg));
  if (!(initloadFlc_P(seg)))
    {
      unlck(seg_Lck(seg));
      return null;
    }
  else if ((seg_FlcLen(seg))<=0)
    {
      unlck(seg_Lck(seg));
      if (!(realerr_P(flcFill(seg))))
	continue LcreateNewBlkEnt;
      else return null;
    }
  else {
    seg_SetFlcLen(seg, (seg_FlcLen(seg))-1);
    {
      int bnum = seg_Flc(seg)[seg_FlcLen(seg)];
      unlck(seg_Lck(seg));
      {
	Ent ent = getEnt(seg, bnum, accwrite);
	if (a2b(ent))
	  ent_SetDty(ent, true);
	return ent;
      }
    }
  }
}
}

/*  End of stuff to deal with the free-list-cache (FLC) */

/*  try-get-ent returns an entry with accmode or #f if blk is lcked. */
/*  When you are done with the entry you need to release-ent!. */

public static Ent tryGetEnt(Seg seg,int blkNum,int accmode)
{
  {
    Ent buk = getBukWait(seg_Id(seg), blkNum);
    {
      Ent ent = buk;
Lentloop: while (true) {
      if (!(a2b(ent)))
	{
	  relBuk(seg_Id(seg), blkNum);
	  tgeFct = 1+(tgeFct);
	  return null;
	}
      else if (!((seg)==(ent_Seg(ent))
	      && (blkNum)==(ent_Id(ent))))
	{
	  ent = ent_Next(ent);
	  continue Lentloop;
	}
      else if ((blk_Id(ent_Blk(ent)))!=(blkNum))
	{
	  relBuk(seg_Id(seg), blkNum);
	  System.err.print(">>>>ERROR<<<< corrutped buffer "+(seg_Id(ent_Seg(ent)))+":"+(blk_Id(ent_Blk(ent)))+" <> "+(blkNum)+"\n");
	  tgeFct = 1+(tgeFct);
	  return null;
	}
      else if ((accnone)==(accmode))
	{
	  ent_SetRef(ent, 1+(ent_Ref(ent)));
	  relBuk(seg_Id(seg), blkNum);
	  tgeCt = 1+(tgeCt);
	  return ent;
	}
      else if ((accnone)==(ent_Acc(ent)))
	{
	  ent_SetAcc(ent, accmode);
	  ent_SetRef(ent, 1+(ent_Ref(ent)));
	  relBuk(seg_Id(seg), blkNum);
	  tgeCt = 1+(tgeCt);
	  return ent;
	}
      else {
	relBuk(seg_Id(seg), blkNum);
	tgeFct = 1+(tgeFct);
	return null;
      }
      }
    }
  }
}


public static Ent chainFindEnt(Han han,int accmode,byte []keyStr,int kLen,int []pkt)
{
  Ent ent = (cacheEntEnable_P
      && a2b(han_Last(han))
    ?tryGetEnt(han_Seg(han), han_Last(han), accmode)
    :null);
  if (a2b(ent)
      && leaf_P(ent_Blk(ent))
      && (blk_TopId(ent_Blk(ent)))==(han_Id(han))
      && blk_FindPos(ent_Blk(ent), keyStr, kLen, pkt)
      && ((pkt_MatchType(pkt))==(match)
	     || ((pkt_MatchType(pkt))==(pastp)
		        || (pkt_MatchType(pkt))==(qpastp))
		    && (pkt_MatchPos(pkt))>(blkDataStart)))
    {
      tceCt = (tceCt)+1;
      return ent;
    }
  else {
    if (a2b(ent))
      releaseEnt(ent, accmode);
    tceFct = (tceFct)+1;
    ent = getEnt(han_Seg(han), han_Id(han), accnone);
    if ((!(root_P(ent_Blk(ent)))
        || blk_Typ_P(ent_Blk(ent), seqTyp)))
      {
	System.err.print(">>>>ERROR<<<< "+("btOpen")+": not a B-tree root "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+"\n");
	releaseEnt(ent, accnone);
	ent = null;
      }
    else ent = findEnt(ent, leaf,  -1, keyStr, kLen);
    if (!(a2b(ent)))
      ;
    else if ((accread)==(accmode))
      ;
    else if (ents_EntUpdateAccess_P(ent, accread, accmode))
      ;
    else {
      releaseEnt(ent, accread);
      ent = null;
    }
    if (a2b(ent))
      ent = chainFind(ent, accmode, keyStr, kLen, pkt);
    if (a2b(ent))
      han_SetLast(han, ent_Id(ent));
    return ent;
  }
}

/*  I havent put the call to PREV:PREV-K-ENT inside here, */
/*  as both paths need to call it - rjz */


public static Ent chainFindPrevEnt(Han han,int accmode,byte []keyStr,int kLen,int []pkt)
{
  Ent ent = (cacheEntEnable_P
      && a2b(han_Last(han))
    ?tryGetEnt(han_Seg(han), han_Last(han), accmode)
    :null);
  if (a2b(ent)
      && leaf_P(ent_Blk(ent))
      && (blk_TopId(ent_Blk(ent)))==(han_Id(han))
      && blk_FindPos(ent_Blk(ent), keyStr, kLen, pkt)
      && ((pkt_MatchType(pkt))==(match)
	     || (pkt_MatchType(pkt))==(matchend)
	     || ((pkt_MatchType(pkt))==(pastp)
		        || (pkt_MatchType(pkt))==(qpastp))
		    && (pkt_MatchPos(pkt))>(blkDataStart)))
    {
      tceCt = (tceCt)+1;
      return ent;
    }
  else {
    if (a2b(ent))
      releaseEnt(ent, accmode);
    tceFct = (tceFct)+1;
    ent = prev_FindPrevEnt(getEnt(han_Seg(han), han_Id(han), accnone), leaf,  -1, keyStr, kLen);
    if (!(a2b(ent)))
      ;
    else if ((accmode)==(accread))
      ;
    else if (ents_EntUpdateAccess_P(ent, accread, accmode))
      ;
    else {
      releaseEnt(ent, accread);
      ent = null;
    }
    return ent;
  }
}

/* (REL-BUK! (SEG:ID seg) blk-num) */
/* (edprintf "all ents in use!\n") */


public static Ent getEnt(Seg seg,int blkNum,int accmode)
{
  if (0 > (blkNum))
    {
      System.err.print(">>>>ERROR<<<< negative block number "+(blkNum)+"\n");
      return null;
    }
  else if ((blkNum)>=(seg_Used(seg)))
    {
      System.err.print(">>>>ERROR<<<< bad block number "+(seg_Id(seg))+":"+(blkNum)+" (>= "+(seg_Used(seg))+")\n");
      return null;
    }
  else {
    Ent ent = getBukWait(seg_Id(seg), blkNum);
Lentloop: while (true) {
    if (!(a2b(ent)))
      {
	ent = tryGetFreeEnt(seg, blkNum);
	if (a2b(ent))
	  {
	    ent_SetNext(ent, getBuk(seg_Id(seg), blkNum));
	    setBuk(seg_Id(seg), blkNum, ent);
	    ent_SetAcc(ent, accpend);
	    ent_SetSeg(ent, seg);
	    ent_SetId(ent, blkNum);
	    ent_SetAge(ent,  -127);
	    ent_SetDty(ent, null);
	    ent_SetPus(ent, 0);
	    ent_SetRef(ent, 1);
	    relBuk(seg_Id(seg), blkNum);
	    if ((accmode)==(accwrite))
	      {
		ent_SetAcc(ent, accwrite);
		ent_SetDty(ent, true);
		initLeafBlk(ent_Blk(ent), blkNum, indTyp);
		geCt = 1+(geCt);
		return ent;
	      }
	    else if (blkio_Read(seg_Port(seg), ent_Blk(ent), seg_Bsiz(seg), blkNum))
	      {
		ent_SetAcc(ent, accmode);
		if ((blk_Id(ent_Blk(ent)))!=(blkNum))
		  System.err.print(">>>>ERROR<<<< corrupted blk "+(seg_Id(ent_Seg(ent)))+":"+(blkNum)+" <> "+(blk_Id(ent_Blk(ent)))+"\n");
		geCt = 1+(geCt);
		return ent;
	      }
	    else {
	      ent_SetRef(ent, 0);
	      ent_SetAcc(ent, accnone);
	      geFct = 1+(geFct);
	      return null;
	    }
	  }
	else {
	  ent = getBukWait(seg_Id(seg), blkNum);
	  continue Lentloop;
	}
      }
    else if (!((seg)==(ent_Seg(ent))
	    && (blkNum)==(ent_Id(ent))))
      {
	ent = ent_Next(ent);
	continue Lentloop;
      }
    else if ((blk_Id(ent_Blk(ent)))!=(blkNum))
      {
	relBuk(seg_Id(seg), blkNum);
	System.err.print(">>>>ERROR<<<< corrupted buffer "+(seg_Id(ent_Seg(ent)))+":"+(blk_Id(ent_Blk(ent)))+" <> "+(blkNum)+"\n");
	geFct = 1+(geFct);
	return null;
      }
    else if ((accnone)==(accmode))
      {
	ent_SetRef(ent, 1+(ent_Ref(ent)));
	relBuk(seg_Id(seg), blkNum);
	geCt = 1+(geCt);
	return ent;
      }
    else if ((accnone)==(ent_Acc(ent)))
      {
	ent_SetAcc(ent, accmode);
	ent_SetRef(ent, 1+(ent_Ref(ent)));
	relBuk(seg_Id(seg), blkNum);
	geCt = 1+(geCt);
	return ent;
      }
    else {
      relBuk(seg_Id(seg), blkNum);
      geFct = 1+(geFct);
      return null;
    }
    }
  }
}


public static Ent switchEnt(Ent oldEnt,int oldacc,int newNum,int newacc)
{
  {
    Ent newEnt = getEnt(ent_Seg(oldEnt), newNum, accnone);
    releaseEnt(oldEnt, oldacc);
    if (a2b(newEnt))
      ents_EntUpdateAccess_P(newEnt, accnone, newacc);
    return newEnt;
  }
}

/* minimum real NUM-ENTS-CT is 12*number of processes */
/* minimum NUM-BUKS IS 2, MAYBE 3 (due to how get-free-ent works) */
/* minimum real BLK-SIZE is 1.5K */


public static int initWb(int maxNumEntsCnt,int maxNumBuks,int maxBlkSize)
{
  if (!(0xc<=(maxNumEntsCnt)))
    {
      System.err.print(">>>>ERROR<<<< "+("initWb")+": "+("maxNumEntsCnt")+" ("+(maxNumEntsCnt)+") must be "+0xc
   +" or greater.\n");
      return argerr;
    }
  else if (!(0xc<=(maxNumBuks)))
    {
      System.err.print(">>>>ERROR<<<< "+("initWb")+": "+("maxNumBuks")+" ("+(maxNumBuks)+") must be "+0xc
   +" or greater.\n");
      return argerr;
    }
  else if (!(0x80<=(maxBlkSize)))
    {
      System.err.print(">>>>ERROR<<<< "+("initWb")+": "+("maxBlkSize")+" ("+(maxBlkSize)+") must be "+0x80
   +" or greater.\n");
      return argerr;
    }
  else 
  lck(segChainLck);
  if (tryLck_P(segChainLck))
    {
      System.err.print(">>>>ERROR<<<< "+("initWb")+": lck (mutex) is not self-blocking!\n");
      return strangerr;
    }
  else if (!(a2b(lckTab)))
    {
      blkio_Init();
      clearStats();
      segCntr = 4;
      numBuks = maxNumBuks;
      blkSize = maxBlkSize;
      freeBukCntr = 0;
      flushEntCntr = 0;
      bukTab = new Ent[numBuks];
      lckTab = new Lck[numBuks];
      entTab = new Ent[entTabInc];
      {
	int i = numBuks;
	while (!(0==(i))) {
	  lckTab[(i)-1] = makeLck((i)-1);
	  {
	    i = (i)-1;
	  }
	}
      }
      lck(freeEntLck);
      {
	int i = maxNumEntsCnt;
	Ent bent = null;
	while (!(0==(i))) {
	  {
	    Ent newent = ent_MakeEnt(numEntsCt);
	    if (a2b(newent))
	      {
		ent_SetNext(newent, bent);
		bent = newent;
		entTab[numEntsCt] = newent;
		ent_SetTag(newent, numEntsCt);
		numEntsCt = 1+(numEntsCt);
		if (0==((numEntsCt)%(entTabInc)))
		  {
		    Ent []tmpEntTab = (Ent[]) resizeArray(entTab, (int)((entTabInc)+(numEntsCt)));
		    if (a2b(tmpEntTab))
		      {
			entTab = tmpEntTab;
		      }
		    else i = 1;
		  }
	      }
	    else i = 1;
	  }
	  {
	    i = (i)-1;
	  }
	}
	freeEnts = bent;
      }
      unlck(freeEntLck);
      unlck(segChainLck);
      return numEntsCt;
    }
  else if ((maxBlkSize)>(blkSize))
    {
      System.err.print(">>>>ERROR<<<< "+("initWb")+": already initialized with smaller blk-size: "+(maxBlkSize)+">"+(blkSize)+"\n");
      unlck(segChainLck);
      return argerr;
    }
  else {
    System.err.print(""+("initWb")+": already initialized\n");
    unlck(segChainLck);
    return notpres;
  }
}


public static int finalWb()
{
  if (a2b(lckTab))
    {
      {
	Seg seg = segChain;
	while (a2b(seg)) {
	  lck(segChainLck);
	  closeSeg(seg, true);
	  unlck(segChainLck);
	  {
	    seg = segChain;
	  }
	}
      }
      {
	int i = numEntsCt;
	while (!(0==(i))) {
	  
	  entTab[ -1+(i)] = null;
	  numEntsCt =  -1+(numEntsCt);
	  {
	    i = (i)-1;
	  }
	}
      }
      {
	int i = numBuks;
	while (!(0==(i))) {
	  
	  lckTab[(i)-1] = null;
	  {
	    i = (i)-1;
	  }
	}
      }
      
      entTab = null;
      
      lckTab = null;
      
      bukTab = null;
      blkio_Final();
      return success;
    }
  else {
    System.err.print(""+("finalWb")+": already finaled\n");
    blkio_Final();
    return success;
  }
}


public static void checkBlk(byte []blk)
{
  {
    int bEnd = blk_End(blk);
    {
      int bPos = blkDataStart;
Llp: while (true) {
      {
	int sPos = nextField(blk, 1+(bPos));
	if ((sPos)==(bEnd))
	  
	  return;
	else if ((sPos)<(bEnd))
	  {
	    {
	      bPos = nextCnvpair(blk, bPos);
	      continue Llp;
	    }
	  }
	else {
	  System.err.print(">>>>ERROR<<<< "+("checkBlk")+": blk "+(blk_Id(blk))+" past end "+(sPos)+"\n");
	  
	  return;
	}
      }
      }
    }
  }
}


public static void checkKeyOrder(byte []blk)
{
  byte []splitStr = new byte[0x100];
  int spos = splitKeyPos(blk);
  if (0 < (spos))
    reconThisKey(blk, spos, splitStr, 0, 0x100);
    return;
}


public static int doSegBuffers(Seg seg,java.lang.reflect.Method func)
{
  {
    int i = numBuks;
    Ent ent = null;
Llp: while (true) {
    if (!(a2b(ent)))
      if (0==(i))
	return success;
      else {
	int T_i = (i)-1;
	ent = bukTab[(i)-1];
	i = T_i;
	continue Llp;
      }
    else if ((!(a2b(seg))
        || (seg)==(ent_Seg(ent))))
      {
	int ans = intFunInvoke(func, null, new Object[] {ent});
	if (success_P(ans))
	  {
	    ent = ent_Next(ent);
	    continue Llp;
	  }
	else return ans;
      }
    else {
      ent = ent_Next(ent);
      continue Llp;
    }
    }
  }
}


public static int checkBuffer(Ent ent)
{
  if (!(0==(ent_Ref(ent))))
    {
      System.err.print(">>>>ERROR<<<< Entry still referenced: "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+"\n");
      ent_SetRef(ent, 0);
    }
  if ((accnone)!=(ent_Acc(ent)))
    {
      System.err.print(">>>>ERROR<<<< Entry still lcked: "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+"\n");
      ents_EntUpdateAccess_P(ent, ent_Acc(ent), accnone);
    }
  return success;
}


public static void checkAccess()
{
  checkLcks();
  doSegBuffers(null, getMethod("wb.Ents", "checkBuffer", new Class[]{Ent.class}));
  return;
}


/*  This routine needs to deal with lck issues. */
/*  TBD needs to give error if lcked. */

public static int flushBuffer(Ent ent)
{
  if ((accnone)!=(ent_Acc(ent)))
    return terminated;
  else if (ent_Dty_P(ent))
    if (ents_EntWrite(ent))
      return success;
    else return retryerr;
  else return success;
}


public static int purgeBuffer(Ent ent)
{
  if (ent_Dty_P(ent))
    {
      if (((ent_Acc(ent))==(accwrite)
	  || (ent_Acc(ent))==(accpend)))
	System.err.print("  Purging "+(((ent_Acc(ent))==(accwrite)
	?"ACCWRITE"
	:"ACCPEND"))+" entry: "+(seg_Id(ent_Seg(ent)))+":"+(ent_Id(ent))+"\n");
      ents_EntWrite(ent);
    }
  amnesiaEnt(ent);
  return success;
}

}
