shithub: dddb

ref: 2ab7efc23fd2137ce88d328441900e0a439a3508
dir: /appl/cmd/dddb.b/

View raw version
implement Dddb;

include "sys.m";
	sys: Sys;
include "arg.m";
include "draw.m";
include "readdir.m";
	readdir: Readdir;
include "string.m";
	strm: String;
include "lists.m";
	lists: Lists;
include "arrays.m";
	arrays: Arrays;
include "convcs.m";
	convcs: Convcs;

include "config.b";
include "ctlfs.b";
include "nodereg.b";

stderr: ref Sys->FD;
debug: int;

DBVER:	con "v0.1.0";
DCS:	con "utf-8";

error(s: string)
{
	sys->fprint(stderr, "dddb: %s\n", s);
	raise "dddb:error";
}

Epoolnotfound	: con "pool not found";
Epoolavail		: con "pool not available";

Dddb: module {
	init: fn(nil: ref Draw->Context, args: list of string);

	# Configuration section
	Config: adt {
		name:		string;
		sysn:		string;
		addr:		string;
		storage:	string;
		fswrks:		int;
		nodes:		list of NodeConfig;

		open:		fn(nodename: string, mtpt: string): Config;
	};

	NodeConfig: adt {
		name:		string;
		sysn:		string;
		addr:		string;
		keyfile:	string;
		storage:	string;
		psize:		int;
		fswrks:		int;

		new:		fn(entry: ref Dbentry): NodeConfig;
	};

	# Registry section
	RegTMsg: adt {
		pick {
		GetNodes =>
		ChanClose =>
		RefreshAll =>
		Check or Refresh or Close =>
			nodename:	string;
		}
	};

	RegRMsg: adt {
		pick {
		Error =>
			err:		string;
		StatusAll =>
			status:		list of ref RegRMsg.Status;
		Status =>
			count:		int;
			poolsize:	int;
		NodeList =>
			names:		list of string;
		}
	};

	NodePool: adt {
		cfg:		NodeConfig;
		instances:	list of string;

		init:		fn(r: self ref NodePool): int;
		check:		fn(r: self ref NodePool): int;
		refresh:	fn(r: self ref NodePool): int;
		newinst:	fn(r: self ref NodePool, mtpt: string): string;
		close:		fn(r: self ref NodePool);
	};

	DbRegistry: adt {
		nodepools:	list of ref NodePool;
		# rchans:		list of chan of ref RegRMsg;
		# tchans:		list of chan of ref RegTMsg;

		new:		fn(cfgs: list of NodeConfig): ref DbRegistry;
		init:		fn(r: self ref DbRegistry);
		# run:		fn(r: self ref DbRegistry);
		changen:	fn(r: self ref DbRegistry): (chan of ref RegTMsg, chan of ref RegRMsg);
		close:		fn(r: self ref DbRegistry);
	};
};

init(nil: ref Draw->Context, args: list of string)
{
	sys = load Sys Sys->PATH;
	arg := load Arg Arg->PATH;
	readdir = load Readdir Readdir->PATH;
	strm = load String String->PATH;
	lists = load Lists Lists->PATH;
	arrays = load Arrays Arrays->PATH;
	convcs = load Convcs Convcs->PATH;
	dial = load Dial Dial->PATH;
	auth = load Auth Auth->PATH;
	keyring = load Keyring Keyring->PATH;

	if(sys == nil)
		error("dddb: sys module not found");
	if(arg == nil)
		error("dddb: arg module not found");
	if(readdir == nil)
		error("dddb: readdir module not found");
	if(strm == nil)
		error("dddb: strm module not found");
	if(lists == nil)
		error("dddb: lists module not found");
	if(convcs == nil)
		error("dddb: convcs module not found");
	if(dial == nil)
		error("dddb: dial module not found");
	if(auth == nil)
		error("dddb: auth module not found");
	if(keyring == nil)
		error("dddb: keyring module not found");

	convcs->init(nil);
	(btos, btoserr) := convcs->getbtos(DCS);
	if(btos == nil)
		error(sys->sprint("dddb: %s character set: %s", DCS, btoserr));
	(stob, stoberr) := convcs->getstob(DCS);
	if(stob == nil)
		error(sys->sprint("dddb: %s character set: %s", DCS, stoberr));

	stderr = sys->fildes(2);
	cfgpath: string = "";
	keyfile: string = nil;
	algs: list of string = nil;

	arg->init(args);
	arg->setusage(arg->progname()+ " [-d] [-k keyfile] [-C algs] [-c config] nodename");
	while((c := arg->opt()) != 0)
		case c {
		'd' => debug++;
		'c' => cfgpath = arg->earg();
		'k' => keyfile = arg->earg();
		'C' =>
			algsstr := arg->earg();
			(nil, algs) = sys->tokenize(algsstr, ",");
		* =>
			sys->fprint(stderr, "bad option: -%c\n", c);
			arg->usage();
		}

	args = arg->argv();

	if(len args != 1) {
		sys->fprint(stderr, "dddb: bad usage\n");
		arg->usage();
	}

	nodename := hd args;

	if(debug)
		sys->fprint(stderr, "dddb: opening config file\n");
	cfg := Config.open(nodename, cfgpath);

	if(debug) {
		sys->fprint(stderr, "dddb: database parms:\n");
		sys->fprint(stderr, "cfg.name: %s\n", cfg.name);
		sys->fprint(stderr, "cfg.sysn: %s\n", cfg.sysn);
		sys->fprint(stderr, "cfg.storage: %s\n", cfg.storage);
		sys->fprint(stderr, "cfg.fswrks: %d\n", cfg.fswrks);
	}

	if(debug)
		sys->fprint(stderr, "dddb: creating and running node registry\n");

	sys->pctl(Sys->NEWPGRP, nil);

	dbreg := DbRegistry.new(cfg.nodes);
	spawn dbreg.init();
	# spawn dbreg.run();

	if(debug)
		sys->fprint(stderr, "dddb: running ctlfs\n");

	run_ctlfs(cfg, dbreg, keyfile, algs);

	sys->fprint(stderr, "dddb: performing shutdown\n");
	dbreg.close();
	sys->fprint(stderr, "dddb: all components shut off\n");
}

user(): string
{
	user := readfile("#c/user");
	if(user == nil)
		return "none";

	return user;
}

readfile(file: string): string
{
	fd := sys->open(file, Sys->OREAD);
	if(fd == nil)
		return nil;

	buf := array[1024] of byte;
	n := sys->read(fd, buf, len buf);
	if(n < 0)
		return nil;

	return string buf[0:n];
}

writefile(file: string, s: string): int
{
	fd := sys->open(file, Sys->OWRITE);
	if(fd == nil)
		return -1;

	buf := array of byte s;
	n := sys->write(fd, buf, len buf);

	return n;
}

dir(name: string, perm: int, qid: big): Sys->Dir
{
	d := sys->zerodir;
	user := user();
	d.name = name;
	d.uid = user;
	d.gid = user;
	d.qid.path = qid;
	if (perm & Sys->DMDIR)
		d.qid.qtype = Sys->QTDIR;
	else
		d.qid.qtype = Sys->QTFILE;
	d.mode = perm;
	return d;
}

diru(name: string, perm: int, qid: big, user: string): Sys->Dir
{
	d := sys->zerodir;
	d.name = name;
	d.uid = user;
	d.gid = user;
	d.qid.path = qid;
	if (perm & Sys->DMDIR)
		d.qid.qtype = Sys->QTDIR;
	else
		d.qid.qtype = Sys->QTFILE;
	d.mode = perm;
	return d;
}

joinstr(items: list of string, sep: string): string
{
	s := "";
	citem := hd items;
	items = tl items;
	s = s + citem;
	while(items != nil) {
		citem = hd items;
		items = tl items;
		s = s + sep + citem;
	}
	return s;
}