Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/ndb/glean/db.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <ip.h>
#include "nbcache.h"

static Node *Hosts;
static Node *Domains;
static QLock Dblk;

/* these attributes may appear multiple times for a given host */
	
static int
singleton(char *name)
{
	int i;
	static char *multivalue[] = { "ip", "ether",  "member", "txt", "srv", "failed" };

	for(i = 0; i < nelem(multivalue); i++)
		if(strcmp(name, multivalue[i]) == 0)
			return 0;
	return 1;
}

static int
cmpattr(char *s1, char *s2)
{
	int i, j;
	static char *order[] = {
		"dc", "bdc", "dmb", "lmb", "bmb", 
		"ether", "ip", "dom", "domain", "srv", "hinfo", "txt"
	};


	for(i = 0; i < nelem(order); i++)
		if(strcmp(order[i], s1) == 0)
			break;
	for(j = 0; j < nelem(order); j++)
		if(strcmp(order[j], s2) == 0)
			break;
	if(i == j)
		return strcmp(s1, s2);
	return i - j;
}

static void
reapattrs(Attr **ap, int force)
{
	Attr *a;
	long ttl, now;

	now = time(nil);
	while(*ap){
		a = *ap;
		ttl = a->ttl;
		if(ttl == -1)
			ttl = Defttl;
		if(now > a->mtime+ttl || force){
			if(Debug == 1)
				print("reap attr %s=%s ttl=%ld age=%ld hits=%ld\n",
					a->name, a->value, a->ttl, now - a->mtime, a->hits);
			if(a->child)
				reapattrs(&a->child, 1);
			*ap = a->next;
			free(a->name);
			free(a->value);
			free(a);
		}
		else
			ap = &a->next;
	}
}

static void
reapnodes(Node **np)
{
	Node *n;
	long ttl, now;

	now = time(nil);
	while(*np){
		n = *np;
		ttl = n->ttl;
		if(ttl == -1)
			ttl = Defttl;
		if(now > n->mtime+ttl){
			if(Debug == 1)
				print("reap node %s ttl=%ld age=%ld hits=%ld\n",
					n->value, n->ttl, now - n->mtime, n->hits);
			if(n->attrs)
				reapattrs(&n->attrs, 1);
			*np = n->next;
			free(n->value);
			free(n);
		}
		else{
			if(n->attrs)
				reapattrs(&n->attrs, 0);
			np = &n->next;
		}
	}
}

/*
 * NB: the value param is smprint()'ed in setval() below
 */
static Attr *
doset(Attr **ap, long ttl, char *name, char *value)
{
	Attr *a, *new;
	int n, unique;

	unique = singleton(name);
	for(a = *ap; a; ap = &a->next, a = *ap){
		n = cmpattr(a->name, name);
		if(n == 0 && (unique || strcmp(value, a->value) == 0)){
			if(Debug && n == 0 && strcmp(value, a->value) != 0)
				print("%s=%s -> %s\n", name, a->value, value);
			free(a->value);
			a->mtime = time(nil);
			a->hits++;
			a->value = value;
			if(ttl > a->ttl){
				if(Debug == 1)
					print("doset: %s=%s ttl=%ld->%ld\n", name, value, a->ttl, ttl);
				a->ttl = ttl;
			}
			if(Debug == 2)
				print("doset: %s=%s refresh %ld/%ld\n", name, value,
					a->ttl - (time(nil) - a->mtime), a->ttl);
			return a;
		}
		if(n > 0)
			break;
	}
	
	if((new = mallocz(sizeof(Attr), 1)) == nil)
		sysfatal("No memory %r\n");
	if((new->name = strdup(name)) == nil)
		sysfatal("No memory %r\n");
	new->ttl = ttl;
	new->mtime = time(nil);
	new->hits++;
	new->value = value;
	new->next = a;
	*ap = new;
	return new;
}

static void
dumptab(Fmt *f, char *name, Node *tab, int first_special)
{
	Node *n;
	Attr *a, *c;
	long ttl, now;

	now = time(nil);
	for(n = tab; n; n = n->next){
		ttl = n->ttl;
		if(ttl == -1)
			ttl = Defttl;
		if(now > n->mtime+ttl)
			continue;
		fmtprint(f, "%s=%q", name, n->value);
		if(! first_special)
			fmtprint(f, "\n");
		for(a = n->attrs; a; a = a->next){
			if(*a->value)
				fmtprint(f, "\t%s=%q", a->name, a->value);
			else
				fmtprint(f, "\t%s=", a->name);
			for(c = a->child; c; c = c->next){
				if(*c->value)
					fmtprint(f, " %s=%q", c->name, c->value);
				else
					fmtprint(f, " %s=", c->name);
			}
			fmtprint(f, "\n");
		}
		fmtprint(f, "\n");
	}
}

int
lookval(Attr *a, char *name)
{
	int rc;
	long now;

	rc = 0;
	now = time(nil);
	qlock(&Dblk);
	for(; a; a = a->next)
		if(cmpattr(a->name, name) == 0){
			a->mtime = now;
			a->hits++;
			for(a = a->child; a; a = a->next){
				a->mtime = now;
				a->hits++;
			}
			rc = 1;
			break;
		}
	qunlock(&Dblk);
	return rc;
}

void
addval(Attr *a, char *name, char *fmt, ...)
{
	va_list arg;
	char *value;

	value = nil;
	if(fmt){
		va_start(arg, fmt);
		if((value = vsmprint(fmt, arg)) == nil)
			sysfatal("No memory %r\n");
		setmalloctag(value, getcallerpc(&a));
		va_end(arg);
	}

	qlock(&Dblk);
	doset(&a->child, a->ttl, name, value);
	qunlock(&Dblk);
}

Attr *
setval(Node *n, char *name, char *fmt, ...)
{
	Attr *a;
	va_list arg;
	char *value;

	va_start(arg, fmt);
	if((value = vsmprint(fmt, arg)) == nil)
		sysfatal("No memory %r\n");
	setmalloctag(value, getcallerpc(&n));
	va_end(arg);

	qlock(&Dblk);
	if(n->attrs)
		reapattrs(&n->attrs, 0);
	a = doset(&n->attrs, n->ttl, name, value);
	qunlock(&Dblk);

	return a;
}

Node *
getnode(int type, long ttl, char *fmt, ...)
{
	long now;
	va_list arg;
	Node *n, **rootp;
	char *name, *value;

	now = time(nil);
	va_start(arg, fmt);
	if((value = vsmprint(fmt, arg)) == nil)
		sysfatal("No memory %r\n");
	setmalloctag(value, getcallerpc(&type));
	va_end(arg);

	qlock(&Dblk);

	switch(type){
	case Thost:
		name="sys";
		rootp = &Hosts;
		break;
	case Tdomain:
		name="domain";
		rootp = &Domains;
		break;
	default:
		SET(name);
		SET(rootp);
		sysfatal("%d - unknown object ID\n", type);
	}

	reapnodes(rootp);
	for(n = *rootp; n; n = n->next)
		if(strcmp(n->value, value) == 0){
			if(Debug == 2)
				print("getnode: %s=%s refresh %ld/%ld hits=%ld %p\n", name, value,
					n->ttl - (now - n->mtime), n->ttl, n->hits, n->attrs);
			n->mtime = now;
			n->hits++;
			if(ttl > n->ttl){
				if(Debug == 2)
					print("getnode: %s ttl=%ld->%ld hits=%ld\n",
						value, n->ttl, ttl, n->hits);
				n->ttl = ttl;
			}
			break;
		}
	qunlock(&Dblk);
	if(n){
		free(value);
		return n;
	}

	if((n = mallocz(sizeof(Node), 1)) == nil)
		sysfatal("No memory %r\n");
	n->mtime = time(nil);
	n->hits++;
	n->ttl = ttl;
	n->value = value;
	if(Debug == 1)
		print("getnode: %s=%s new-node ttl=%ld\n", name, value, n->ttl);

	qlock(&Dblk);
	n->next = *rootp;
	*rootp = n;
	qunlock(&Dblk);

	return n;
}

char *
snapshot(void)
{
	Fmt fmt;

	fmtstrinit(&fmt);
	qlock(&Dblk);
	dumptab(&fmt, "domain", Domains, 0);
	dumptab(&fmt, "sys", Hosts, 1);
	qunlock(&Dblk);
	return fmtstrflush(&fmt);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.