/*
 * seen.c Copyright 1999 Christopher M Sedore. All Rights Reserved.
 * Please see the "COPYING" file for license details.
 * 
 * Implements a simple mmapped database for hashes of message-id's that
 * have been "seen" already.
 */

#include "main.h"
#include "seen.h"
unsigned int seenDataCount=50000,seenTableSize=51997;
char seentablepath[MAX_PATH],seendatapath[MAX_PATH];
unsigned int seenDepth=0,seenMaxDepth=0,seenSearchCount=0;

SEENITEM *seenDB;
SEENHEADER *seenHeader;
unsigned int *seenTable;

unsigned int falloutTime,currentTime;

#define TRUE 1
#define FALSE 0

unsigned int
CheckSeen(u_quad_t id)
{
  unsigned int ptr,slot,start,tdepth=0;
  
  seenSearchCount++;


  slot=id%seenTableSize;

  if (seenTable[slot]<=seenDataCount) {
	  start=ptr=seenTable[slot];
	  while (1) {
		  if (seenDB[ptr].id==id) {
			  return TRUE;
		  }

		  if (seenDB[ptr].next>seenDataCount) {
			  return FALSE;
		  }
		  if (ptr<=seenHeader->position) {
            if ((seenDB[ptr].next>=ptr) &&
				(seenDB[ptr].next<=seenHeader->position))
				return FALSE;
		  } else {
            if ((seenDB[ptr].next<=seenHeader->position) ||
				(seenDB[ptr].next>=ptr)) 
				return FALSE;
          } 
		  ptr=seenDB[ptr].next;
		  seenDepth++;
		  tdepth++;
		  if (tdepth>seenMaxDepth) {
			  seenMaxDepth=tdepth;
		  }
		  
	  }
  }

  return FALSE;
}


int
AddSeen(u_quad_t id,unsigned int opt) 
{
  unsigned int ptr,slotlock;

  if (CheckSeen(id)) {
	return FALSE;
  }

  ptr=id%seenTableSize;

  seenDB[seenHeader->position].id=id;
  seenDB[seenHeader->position].next=seenTable[ptr];
  seenTable[ptr]=seenHeader->position;
  seenHeader->position++;
  if (seenHeader->position>seenDataCount) {
	  seenHeader->position=0;
  }
  return TRUE;
}

int
seeninit() {
  unsigned int seenDataSize;
  void *s;
  int sz;
  int f;


  sprintf(seentablepath,"%s/seen.idx",GetConfigString("HistoryTablePath"));
  sprintf(seendatapath,"%s/seen.dat",GetConfigString("HistoryDataPath"));

  GetConfigInt("SeenDataCount",&seenDataCount);
  seenDataSize=(seenDataCount*sizeof(SEENITEM))+sizeof(SEENHEADER);

  if (!GetConfigInt("SeenTableSize",&seenTableSize)) {
    seenTableSize=55997;
  }

  f=open(seentablepath,O_RDWR);

  if (f<0) {
    printf("could not open table file\n");
    exit(1);
  }

  seenTable=mmap(NULL,sizeof(unsigned int)*seenTableSize,
			PROT_READ|PROT_WRITE,MAP_SHARED,f,0);

  if (seenTable==NULL) {
    printf("could not map table file\n");
    exit(1);
  }


  f=open(seendatapath,O_RDWR);

  if (f<0) {
    printf("could not open data file\n");
    exit(1);
  }

  s=mmap(NULL,sizeof(SEENITEM)*seenDataCount,
			PROT_READ|PROT_WRITE,MAP_SHARED,f,0);

  if (s==NULL) {
    printf("could not map data file\n");
    exit(1);
  }

  seenHeader=(SEENHEADER *)s;
  seenDB=(SEENITEM *)((unsigned int) s + sizeof(SEENHEADER));

  
  return 0;
}

unsigned int
SeenThread(unsigned int unused) {
	while (1) {
	  printf("seen max depth=%u,seen avg depth=%f,seen search count=%u,pos=%u\n",
		      seenMaxDepth,1.0*seenDepth/seenSearchCount,seenSearchCount,seenHeader->position);
	  usleep(500000);
	}
}

void
SeenInit() {
  seeninit();
}

void
seenclose()
{
}
