New Data Store server.
This commit is contained in:
parent
288860f6e6
commit
d1f2ba26b0
43
servers/ds/Makefile
Normal file
43
servers/ds/Makefile
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# Makefile for Data Store Server (DS)
|
||||||
|
SERVER = ds
|
||||||
|
|
||||||
|
# directories
|
||||||
|
u = /usr
|
||||||
|
i = $u/include
|
||||||
|
s = $i/sys
|
||||||
|
m = $i/minix
|
||||||
|
b = $i/ibm
|
||||||
|
k = $u/src/kernel
|
||||||
|
p = $u/src/servers/pm
|
||||||
|
f = $u/src/servers/fs
|
||||||
|
|
||||||
|
# programs, flags, etc.
|
||||||
|
CC = exec cc
|
||||||
|
CFLAGS = -I$i
|
||||||
|
LDFLAGS = -i
|
||||||
|
LIBS = -lsys -lsysutil
|
||||||
|
|
||||||
|
OBJ = main.o store.o
|
||||||
|
|
||||||
|
# build local binary
|
||||||
|
all build: $(SERVER)
|
||||||
|
$(SERVER): $(OBJ)
|
||||||
|
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||||
|
# install -S 256w $@
|
||||||
|
|
||||||
|
# install with other servers
|
||||||
|
install: /sbin/$(SERVER)
|
||||||
|
/sbin/$(SERVER): $(SERVER)
|
||||||
|
install -o root -c $? $@
|
||||||
|
# install -o root -cs $? $@
|
||||||
|
|
||||||
|
# clean up local files
|
||||||
|
clean:
|
||||||
|
rm -f $(SERVER) *.o *.bak
|
||||||
|
|
||||||
|
depend:
|
||||||
|
/usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
|
||||||
|
|
||||||
|
# Include generated dependencies.
|
||||||
|
include .depend
|
||||||
|
|
7
servers/ds/glo.h
Normal file
7
servers/ds/glo.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/* Global variables. */
|
||||||
|
|
||||||
|
/* The parameters of the call are kept here. */
|
||||||
|
extern int who; /* caller's proc number */
|
||||||
|
extern int callnr; /* system call number */
|
||||||
|
extern int dont_reply; /* normally 0; set to 1 to inhibit reply */
|
||||||
|
|
30
servers/ds/inc.h
Normal file
30
servers/ds/inc.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* Header file including all needed system headers. */
|
||||||
|
|
||||||
|
#define _SYSTEM 1 /* get OK and negative error codes */
|
||||||
|
#define _MINIX 1 /* tell headers to include MINIX stuff */
|
||||||
|
|
||||||
|
#include <ansi.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <minix/callnr.h>
|
||||||
|
#include <minix/config.h>
|
||||||
|
#include <minix/type.h>
|
||||||
|
#include <minix/const.h>
|
||||||
|
#include <minix/com.h>
|
||||||
|
#include <minix/syslib.h>
|
||||||
|
#include <minix/sysutil.h>
|
||||||
|
#include <minix/keymap.h>
|
||||||
|
#include <minix/bitmap.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include "proto.h"
|
||||||
|
#include "glo.h"
|
||||||
|
#include "store.h"
|
||||||
|
|
135
servers/ds/main.c
Normal file
135
servers/ds/main.c
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
/* Data Store Server.
|
||||||
|
* This service implements a little publish/subscribe data store that is
|
||||||
|
* crucial for the system's fault tolerance. Components that require state
|
||||||
|
* can store it here, for later retrieval, e.g., after a crash and subsequent
|
||||||
|
* restart by the reincarnation server.
|
||||||
|
*
|
||||||
|
* Created:
|
||||||
|
* Oct 19, 2005 by Jorrit N. Herder
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "inc.h" /* include master header file */
|
||||||
|
|
||||||
|
/* Allocate space for the global variables. */
|
||||||
|
int who; /* caller's proc number */
|
||||||
|
int callnr; /* system call number */
|
||||||
|
int sys_panic; /* flag to indicate system-wide panic */
|
||||||
|
|
||||||
|
extern int errno; /* error number set by system library */
|
||||||
|
|
||||||
|
/* Declare some local functions. */
|
||||||
|
FORWARD _PROTOTYPE(void init_server, (int argc, char **argv) );
|
||||||
|
FORWARD _PROTOTYPE(void exit_server, (void) );
|
||||||
|
FORWARD _PROTOTYPE(void get_work, (message *m_ptr) );
|
||||||
|
FORWARD _PROTOTYPE(void reply, (int whom, message *m_ptr) );
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* main *
|
||||||
|
*===========================================================================*/
|
||||||
|
PUBLIC int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* This is the main routine of this service. The main loop consists of
|
||||||
|
* three major activities: getting new work, processing the work, and
|
||||||
|
* sending the reply. The loop never terminates, unless a panic occurs.
|
||||||
|
*/
|
||||||
|
message m;
|
||||||
|
int result;
|
||||||
|
sigset_t sigset;
|
||||||
|
|
||||||
|
/* Initialize the server, then go to work. */
|
||||||
|
init_server(argc, argv);
|
||||||
|
|
||||||
|
/* Main loop - get work and do it, forever. */
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
/* Wait for incoming message, sets 'callnr' and 'who'. */
|
||||||
|
get_work(&m);
|
||||||
|
|
||||||
|
switch (callnr) {
|
||||||
|
case SYS_SIG:
|
||||||
|
sigset = (sigset_t) m.NOTIFY_ARG;
|
||||||
|
if (sigismember(&sigset,SIGTERM) || sigismember(&sigset,SIGKSTOP)) {
|
||||||
|
exit_server();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case DS_PUBLISH:
|
||||||
|
result = do_publish(&m);
|
||||||
|
break;
|
||||||
|
case DS_RETRIEVE:
|
||||||
|
result = do_retrieve(&m);
|
||||||
|
break;
|
||||||
|
case DS_SUBSCRIBE:
|
||||||
|
result = do_subscribe(&m);
|
||||||
|
break;
|
||||||
|
case GETSYSINFO:
|
||||||
|
result = do_getsysinfo(&m);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
report("DS","warning, got illegal request from:", m.m_source);
|
||||||
|
result = EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally send reply message, unless disabled. */
|
||||||
|
if (result != EDONTREPLY) {
|
||||||
|
m.m_type = result; /* build reply message */
|
||||||
|
reply(who, &m); /* send it away */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(OK); /* shouldn't come here */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* init_server *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE void init_server(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* Initialize the data store server. */
|
||||||
|
int i, s;
|
||||||
|
struct sigaction sigact;
|
||||||
|
|
||||||
|
/* Install signal handler. Ask PM to transform signal into message. */
|
||||||
|
sigact.sa_handler = SIG_MESS;
|
||||||
|
sigact.sa_mask = ~0; /* block all other signals */
|
||||||
|
sigact.sa_flags = 0; /* default behaviour */
|
||||||
|
if (sigaction(SIGTERM, &sigact, NULL) < 0)
|
||||||
|
report("DS","warning, sigaction() failed", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* exit_server *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE void exit_server()
|
||||||
|
{
|
||||||
|
/* Shut down the information service. */
|
||||||
|
|
||||||
|
/* Done. Now exit. */
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* get_work *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE void get_work(m_ptr)
|
||||||
|
message *m_ptr; /* message buffer */
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
status = receive(ANY, m_ptr); /* this blocks until message arrives */
|
||||||
|
if (OK != status)
|
||||||
|
panic("DS","failed to receive message!", status);
|
||||||
|
who = m_ptr->m_source; /* message arrived! set sender */
|
||||||
|
callnr = m_ptr->m_type; /* set function call number */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* reply *
|
||||||
|
*===========================================================================*/
|
||||||
|
PRIVATE void reply(who, m_ptr)
|
||||||
|
int who; /* destination */
|
||||||
|
message *m_ptr; /* message buffer */
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
s = send(who, m_ptr); /* send the message */
|
||||||
|
if (OK != s)
|
||||||
|
panic("DS", "unable to send reply!", s);
|
||||||
|
}
|
||||||
|
|
10
servers/ds/proto.h
Normal file
10
servers/ds/proto.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/* Function prototypes. */
|
||||||
|
|
||||||
|
/* main.c */
|
||||||
|
_PROTOTYPE(int main, (int argc, char **argv));
|
||||||
|
|
||||||
|
/* store.c */
|
||||||
|
_PROTOTYPE(int do_publish, (message *m_ptr));
|
||||||
|
_PROTOTYPE(int do_retrieve, (message *m_ptr));
|
||||||
|
_PROTOTYPE(int do_subscribe, (message *m_ptr));
|
||||||
|
_PROTOTYPE(int do_getsysinfo, (message *m_ptr));
|
163
servers/ds/store.c
Normal file
163
servers/ds/store.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/* Implementation of the Data Store. */
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
/* Allocate space for the data store. */
|
||||||
|
PRIVATE struct data_store ds_store[NR_DS_KEYS];
|
||||||
|
PRIVATE int nr_in_use;
|
||||||
|
|
||||||
|
PRIVATE _PROTOTYPE(int find_key, (int key, struct data_store **dsp));
|
||||||
|
PRIVATE _PROTOTYPE(int set_owner, (struct data_store *dsp, void *auth_ptr));
|
||||||
|
PRIVATE _PROTOTYPE(int is_authorized, (struct data_store *dsp, void *auth_ptr));
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE int set_owner(dsp, ap)
|
||||||
|
struct data_store *dsp; /* data store structure */
|
||||||
|
void *ap; /* authorization pointer */
|
||||||
|
{
|
||||||
|
/* Authorize the caller. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE int is_authorized(dsp, ap)
|
||||||
|
struct data_store *dsp; /* data store structure */
|
||||||
|
void *ap; /* authorization pointer */
|
||||||
|
{
|
||||||
|
/* Authorize the caller. */
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE int find_key(key, dsp)
|
||||||
|
int key; /* key to look up */
|
||||||
|
struct data_store **dsp; /* store pointer here */
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
|
||||||
|
*dsp = NULL;
|
||||||
|
for (i=0; i<NR_DS_KEYS; i++) {
|
||||||
|
if ((ds_store[i].ds_flags & DS_IN_USE) && ds_store[i].ds_key == key) {
|
||||||
|
*dsp = &ds_store[i];
|
||||||
|
return(TRUE); /* report success */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(FALSE); /* report not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC int do_publish(m_ptr)
|
||||||
|
message *m_ptr; /* request message */
|
||||||
|
{
|
||||||
|
struct data_store *dsp;
|
||||||
|
|
||||||
|
/* Store (key,value)-pair. First see if key already exists. If so,
|
||||||
|
* check if the caller is allowed to overwrite the value. Otherwise
|
||||||
|
* find a new slot and store the new value.
|
||||||
|
*/
|
||||||
|
if (find_key(m_ptr->DS_KEY, &dsp)) { /* look up key */
|
||||||
|
if (! is_authorized(dsp,m_ptr->DS_AUTH)) { /* check if owner */
|
||||||
|
return(EPERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { /* find a new slot */
|
||||||
|
if (nr_in_use >= NR_DS_KEYS) {
|
||||||
|
return(EAGAIN); /* store is full */
|
||||||
|
} else {
|
||||||
|
dsp = &ds_store[nr_in_use]; /* new slot found */
|
||||||
|
dsp->ds_key = m_ptr->DS_KEY;
|
||||||
|
if (! set_owner(dsp,m_ptr->DS_AUTH)) { /* associate owner */
|
||||||
|
return(EINVAL);
|
||||||
|
}
|
||||||
|
dsp->ds_nr_subs = 0; /* nr of subscribers */
|
||||||
|
dsp->ds_flags = DS_IN_USE; /* initialize slot */
|
||||||
|
nr_in_use ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point we have a data store pointer and know the caller is
|
||||||
|
* authorize to write to it. Set all fields as requested.
|
||||||
|
*/
|
||||||
|
dsp->ds_val_l1 = m_ptr->DS_VAL_L1; /* store all data */
|
||||||
|
dsp->ds_val_l2 = m_ptr->DS_VAL_L2;
|
||||||
|
|
||||||
|
/* If the data is public. Check if there are any subscribers to this key.
|
||||||
|
* If so, notify all subscribers so that they can retrieve the data, if
|
||||||
|
* they're still interested.
|
||||||
|
*/
|
||||||
|
if ((dsp->ds_flags & DS_PUBLIC) && dsp->ds_nr_subs > 0) {
|
||||||
|
|
||||||
|
/* Subscriptions are not yet implemented. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return(OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC int do_retrieve(m_ptr)
|
||||||
|
message *m_ptr; /* request message */
|
||||||
|
{
|
||||||
|
struct data_store *dsp;
|
||||||
|
|
||||||
|
/* Retrieve data. Look up the key in the data store. Return an error if it
|
||||||
|
* is not found. If this data is private, only the owner may retrieve it.
|
||||||
|
*/
|
||||||
|
if (find_key(m_ptr->DS_KEY, &dsp)) { /* look up key */
|
||||||
|
|
||||||
|
/* If the data is not public, the caller must be authorized. */
|
||||||
|
if (! dsp->ds_flags & DS_PUBLIC) { /* check if private */
|
||||||
|
if (! is_authorized(dsp,m_ptr->DS_AUTH)) { /* authorize call */
|
||||||
|
return(EPERM); /* not allowed */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data is public or the caller is authorized to retrieve it. */
|
||||||
|
printf("DS retrieves data: key %d (found %d), l1 %u, l2 %u\n",
|
||||||
|
m_ptr->DS_KEY, dsp->ds_key, dsp->ds_val_l1, dsp->ds_val_l2);
|
||||||
|
m_ptr->DS_VAL_L1 = dsp->ds_val_l1; /* return value */
|
||||||
|
m_ptr->DS_VAL_L2 = dsp->ds_val_l2; /* return value */
|
||||||
|
return(OK); /* report success */
|
||||||
|
}
|
||||||
|
return(ESRCH); /* key not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PUBLIC int do_subscribe(m_ptr)
|
||||||
|
message *m_ptr; /* request message */
|
||||||
|
{
|
||||||
|
/* Subscribe to a key of interest. Only existing and public keys can be
|
||||||
|
* subscribed to. All updates to the key will cause a notification message
|
||||||
|
* to be sent to the subscribed. On success, directly return a copy of the
|
||||||
|
* data for the given key.
|
||||||
|
*/
|
||||||
|
return(ENOSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* do_getsysinfo *
|
||||||
|
*===========================================================================*/
|
||||||
|
PUBLIC int do_getsysinfo(m_ptr)
|
||||||
|
message *m_ptr;
|
||||||
|
{
|
||||||
|
vir_bytes src_addr, dst_addr;
|
||||||
|
int dst_proc;
|
||||||
|
size_t len;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
switch(m_ptr->m1_i1) {
|
||||||
|
case SI_DATA_STORE:
|
||||||
|
src_addr = (vir_bytes) ds_store;
|
||||||
|
len = sizeof(struct data_store) * NR_DS_KEYS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_proc = m_ptr->m_source;
|
||||||
|
dst_addr = (vir_bytes) m_ptr->m1_p1;
|
||||||
|
if (OK != (s=sys_datacopy(SELF, src_addr, dst_proc, dst_addr, len)))
|
||||||
|
return(s);
|
||||||
|
return(OK);
|
||||||
|
}
|
||||||
|
|
19
servers/ds/store.h
Normal file
19
servers/ds/store.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/* Type definitions for the Data Store Server. */
|
||||||
|
struct data_store {
|
||||||
|
int ds_flags; /* flags for this store */
|
||||||
|
int ds_key; /* key to lookup information */
|
||||||
|
long ds_val_l1; /* data associated with key */
|
||||||
|
long ds_val_l2; /* data associated with key */
|
||||||
|
long ds_auth; /* secret given by owner of data */
|
||||||
|
int ds_nr_subs; /* number of subscribers for key */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flag values. */
|
||||||
|
#define DS_IN_USE 0x01
|
||||||
|
#define DS_PUBLIC 0x02
|
||||||
|
|
||||||
|
/* Constants for the Data Store Server. */
|
||||||
|
#define NR_DS_KEYS 64 /* reserve space for so many items */
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue