#include <stdio.h>
#include <unistd.h>
#include "copyright.h"
#include "config.h"
#include "db.h"
#include "externs.h"
#include "params.h"
#include "lru.h"
#ifdef USE_DBP
#define BUFFER_LEN 1024
#define FREE_IT 1
#define SAVE_IT 0
#define END_MOVE "***Property list end ***" /* 24 */
#define BEGIN_MOVE "***Property list start ***" /* 26 */
#define MAXOBJS 256
#define FUDGE_FACTOR 32
#define PEROBJECT_FUDGE 55
#define PERLINE_FUDGE 3
/* change this variable on the fly to resize cache. */
/* make it < 1 and you are doomed. */
/* be afraid. be very afraid */
int dbp_max_objects = MAXOBJS;
static int enable = 0;
static int lock = 0;
static FILE *map, *data;
/* calculate the disk space needed to store the property entries for a
single object. There's probably a more elegant solution, but this
one is sure to work.
*/
static int calclen = 0;
static int totallen = 0;
static int digitsin(int x)
{
int y = 1;
while (x /= 10)
y++;
return y;
}
/* old one, it's buggy... I'll buy you a pizza if you can tell me why
-- Doran
static void calc_putprop_recurse(propdir *p)
{
int end;
for (; p; p = p->next)
{
if (p->child)
{
end = calclen;
calclen += strlen(p->name) + 1;
calc_putprop_recurse(p->child);
calclen = end;
}
if (p->data)
{
totallen += calclen + strlen(p->name) +
digitsin(p->perms) + strlen(p->data) + PERLINE_FUDGE;
}
}
}
*/
/* if this one doesn't work I'll hang it up right now. */
char buf[BUFFER_LEN * 16];
char buf2[BUFFER_LEN * 16];
void calc_putprop_recurse(propdir *p)
{
char *end;
for (; p; p = p->next)
{
if (p->child)
{
end = buf2 + strlen(buf2);
strcat(buf2, p->name);
strcat(buf2, "/");
calc_putprop_recurse(p->child);
*end = '\0';
}
if (p->data)
{
sprintf (buf, "%s%s:%d:%s\n", buf2, p->name, p->perms, p->data);
/* fputs(buf, f); */
totallen += strlen(buf);
}
}
}
static int calc_putprop(dbref obj)
{
calclen = totallen = 0;
calc_putprop_recurse(DBFETCHPROP(obj));
return (totallen + PEROBJECT_FUDGE + digitsin(obj));
}
void dbp_lock(void)
{
lock++;
}
void dbp_unlock(void)
{
lock--;
}
int dbp_enable(char *name)
{
char fname[BUFFER_LEN];
sprintf(fname, "%s.map", name);
map = fopen(fname, "r+");
if (map == NULL)
{
fprintf(stderr, "Trouble opening map file %s.\n", fname);
return 1;
}
sprintf(fname, "%s.dat", name);
data = fopen(fname, "r+");
if (data == NULL)
{
fprintf(stderr, "Trouble opening data file %s.\n", fname);
return 1;
}
enable = 1;
return 0;
}
void dbp_disable(void)
{
if (enable != 1)
return;
fclose(map);
fclose(data);
enable = 0;
}
static void dbp_unload(long what, int freeflag)
{
long tmp[2];
int size;
long start, end;
if (enable == 0)
return;
if (lock > 0)
return;
lock++;
size = calc_putprop(what);
if (size <= DBFETCH(what)->dbp_size)
{
fseek(map, sizeof(long) * 2 * (what + 1), SEEK_SET);
fread(tmp, sizeof(long), 2, map);
fseek(data, tmp[1], SEEK_SET);
}
else
{
fseek(data, 0L, SEEK_END);
/* we're bigger now, remember that */
DBSTORE(what, dbp_size, size);
}
if(DBFETCH(what)->properties)
{
tmp[0] = what;
tmp[1] = ftell(data);
}
else
{
tmp[0] = -1L;
tmp[1] = -1L;
DBSTORE(what, dbp_size, -1L);
/* free me do me */
}
fseek(map, sizeof(long) * 2 * (what + 1), SEEK_SET);
fwrite(tmp, sizeof(long), 2, map);
fflush(map);
if (DBFETCH(what)->properties)
{
start = ftell(data);
fprintf(data, "%s - %ld\n", BEGIN_MOVE, what);
putproperties(data, what);
fprintf(data, "%s\n", END_MOVE);
fflush(data);
end = ftell(data);
if ((end - start) != size)
{
/* oh shit, we've got a boo boo, spew errors like */
/* a sunovabitch and exit (we're hopelessly */
/* screwed by this point) */
fprintf(stderr, "DBP: Fatal Error!\n");
fprintf(stderr, " : %ld -> %d/%d\n", what, (end - start), size);
fprintf(stderr, "%s - %ld\n", BEGIN_MOVE, what);
putproperties(stderr, what);
fprintf(stderr, "%s\n", END_MOVE);
exit(0xbabe);
}
if (freeflag == FREE_IT)
{
burn_proptree(DBFETCH(what)->properties);
DBFETCH(what)->properties = NULL;
}
}
lock--;
}
void dbp_load(long what)
{
long offset[2];
if (enable == 0)
return;
if (lock > 0)
return;
lock++;
if (lru_hasp(what) == 1)
{
lock--;
return;
}
if (DBFETCH(what)->properties != NULL)
{
lock--;
lru_use(what);
return;
}
lru_use(what);
offset[0] = sizeof(long) * 2 * (what + 1);
fseek(map, offset[0], SEEK_SET);
fread(offset, sizeof(long), 2, map);
if (offset[0] == -1L || offset[1] == -1L)
{
offset[0] = -1L;
offset[1] = -1L;
fseek(map, sizeof(long) * 2 * (what + 1), SEEK_SET);
fwrite(offset, sizeof(long), 2, map);
fflush(map);
DBSTORE(what, dbp_size, -1);
}
else if (offset[0] == what)
{
fseek(data, offset[1], SEEK_SET);
getproperties(data, what, 1); /* check me do me */
if (DBFETCH(what)->dbp_size == -1L)
DBSTORE(what, dbp_size, calc_putprop(what));
}
while (lru_count() > dbp_max_objects)
dbp_unload(lru_old(), FREE_IT);
lock--;
}
void dbp_flush(void)
{
if (enable == 0)
return;
while (lru_count() > 0)
dbp_unload(lru_old(), FREE_IT);
}
void dbp_sync(void)
{
dbref spot;
if (enable == 0)
return;
for (spot = lru_head(); spot != NOTHING; spot = DBFETCH(spot)->lru_next)
{
dbp_unload(spot, SAVE_IT);
}
}
void dbstoreprop(long what, propdir *p)
{
dbp_load(what);
DBSTORE(what, properties, p);
}
propdir *dbfetchprop(long what)
{
dbp_load(what);
return (DBFETCH(what)->properties);
}
#endif