blob: 483360f8852b0f7d8aa4e68ae9829b8aaabed6dd [file] [log] [blame]
//------------------------------------------------------------------
//
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "seabed/fserr.h"
#include "seabed/ms.h"
#include "seabed/pctl.h"
#include "seabed/pevents.h"
#include "tchkfe.h"
#include "tms.h"
#include "tmsfsutil.h"
#include "tutil.h"
#include "tutilp.h"
bool chk = true;
MS_Mon_Node_Info_Type cinfo;
int cnid = -1;
int cpid = -1;
int gargc;
char **gargv;
char group[20];
char *key;
bool quiesce = false;
char recv_buffer[40000];
char send_buffer[40000];
int snid = -1;
int spid = -1;
MS_Mon_Msg *sys_msg = (MS_Mon_Msg *) recv_buffer;
bool sys_mon_msg;
char *value;
bool verbose = false;
MS_Mon_Zone_Info_Type zinfo, zinfo1, zinfo2;
// forwards
void display_info_entry(int count,
MS_Mon_Zone_Info_Entry_Type *info);
void display_zone_info(const char *str,
MS_Mon_Zone_Info_Type *zone_info);
void srv_process_sm_close_chk();
void srv_process_sm_node_down_chk();
void srv_process_sm_process_death_chk();
const char *srv_sm_lookup(int mt);
void display_info_entry(int count,
MS_Mon_Zone_Info_Entry_Type *info) {
int node;
printf("cluster-nodes=%d\n",
count);
for (node = 0; node < count; node++) {
printf("node[%d].nid=%d, zid=%d, pnid=%d, pstate=%d, node_name=%s\n",
node,
info[node].nid,
info[node].zid,
info[node].pnid,
info[node].pstate,
info[node].node_name);
}
}
void display_zone_info(const char *str, MS_Mon_Zone_Info_Type *zone_info) {
printf("\n");
printf("display_zone_info %s, num-returned=%d\n", str, zone_info->num_returned);
for (int n = 0; n < zone_info->num_returned; n++)
printf(" nid=%d, pnid=%d, zid=%d, pstate=%d, node_name=%s\n",
zone_info->node[n].nid,
zone_info->node[n].pnid,
zone_info->node[n].zid,
zone_info->node[n].pstate,
zone_info->node[n].node_name);
}
void srv_do_change() {
int ferr;
sprintf(group, "NODE%d", snid);
key = (char *) "akey";
value = (char *) "avalue";
ferr = msg_mon_reg_set(MS_Mon_ConfigType_Node, // type
group, // group
key, // key
value); // value
TEST_CHK_FEOK(ferr);
}
void srv_do_shutdown() {
int ferr;
ferr = msg_mon_shutdown(MS_Mon_ShutdownLevel_Normal);
TEST_CHK_FEOK(ferr);
}
void srv_do_start() {
int arg;
int ferr;
char name[MS_MON_MAX_PROCESS_NAME];
int nid;
SB_Phandle_Type phandle;
char prog[MS_MON_MAX_PROCESS_PATH];
sprintf(prog, "%s/%s", getenv("PWD"), gargv[0]);
for (arg = 0; arg < gargc; arg++)
if (strcmp(gargv[arg], "-server") == 0) // start_process
gargv[arg] = (char *) "-die";
nid = -1;
strcpy(name, "$die");
ferr = msg_mon_start_process_nowait(prog, // prog
name, // name
NULL, // ret_name
gargc, // argc
gargv, // argv
TPT_REF(phandle), // phandle
MS_ProcessType_Generic, // ptype
0, // priority
0, // debug
0, // backup
9, // tag
&nid, // nid
NULL, // pid
NULL, // infile
NULL); // outfile
TEST_CHK_FEOK(ferr);
}
void srv_print_sm(int exp_type, int act_type) {
const char *str_act;
const char *str_exp;
if (verbose) {
if (exp_type == -1)
str_exp = "Close|NodeDown|ProcessDeath";
else
str_exp = srv_sm_lookup(exp_type);
str_act = srv_sm_lookup(act_type);
printf("expecting msg-type=%d(%s), actual msg-type=%d(%s)\n",
exp_type, str_exp, act_type, str_act);
}
if (chk) {
assert(exp_type == act_type);
}
}
void srv_process_sm(int exp_type) {
int ferr;
int lerr;
BMS_SRE sre;
if (verbose)
printf("listen before\n");
do {
lerr = XWAIT(LREQ, -1);
TEST_CHK_WAITIGNORE(lerr);
lerr = BMSG_LISTEN_((short *) &sre, // sre
0, // listenopts
0); // listenertag
} while (lerr == XSRETYPE_NOWORK);
ferr = BMSG_READDATA_(sre.sre_msgId, // msgid
recv_buffer, // reqdata
40000); // bytecount
util_check("BMSG_READDATA_", ferr);
sys_mon_msg = (sre.sre_flags & BSRE_MON);
if (verbose) {
if (sys_mon_msg)
printf("listen after sre.flags=0x%x, msg-type=%d(%s)\n",
sre.sre_flags, sys_msg->type, srv_sm_lookup(sys_msg->type));
else
printf("listen after sre.flags=0x%x\n", sre.sre_flags);
}
if (exp_type == 0) {
if (chk) {
assert(!sys_mon_msg);
}
}
if (sys_mon_msg) {
srv_print_sm(exp_type, sys_msg->type);
}
if (verbose)
printf("reply\n");
BMSG_REPLY_(sre.sre_msgId, // msgid
NULL, // replyctrl
0, // replyctrlsize
recv_buffer, // replydata
0, // replydatasize
0, // errorclass
NULL); // newphandle
}
void srv_process_sm_change() {
srv_process_sm(MS_MsgType_Change);
if (chk) {
assert(sys_msg->u.change.type == MS_Mon_ConfigType_Node);
assert(strcmp(sys_msg->u.change.group, group) == 0);
assert(strcasecmp(sys_msg->u.change.key, key) == 0);
assert(strcmp(sys_msg->u.change.value, value) == 0);
}
}
void srv_process_sm_close() {
srv_process_sm(MS_MsgType_Close);
if (chk)
srv_process_sm_close_chk();
}
void srv_process_sm_close_chk() {
assert(sys_msg->u.close.nid == cnid);
assert(sys_msg->u.close.pid == cpid);
assert(strcasecmp(sys_msg->u.close.process_name, "$cli") == 0);
assert(sys_msg->u.close.aborted);
assert(sys_msg->u.close.mon);
}
void srv_process_sm_open() {
int disable;
int ferr;
int node_info_count = 0;
int node_info_max = 0;
MS_Mon_Zone_Info_Entry_Type *zone_info = NULL;
srv_process_sm(MS_MsgType_Open);
if (chk) {
assert(strcasecmp(sys_msg->u.open.target_process_name, "$cli") == 0);
assert(sys_msg->u.open.death_notification);
}
cnid = sys_msg->u.open.nid;
cpid = sys_msg->u.open.pid;
ferr = msg_mon_get_node_info_detail(cnid, &cinfo);
TEST_CHK_FEOK(ferr);
disable = msg_test_assert_disable();
ferr = msg_mon_get_zone_info_detail(-1, -1, &zinfo);
assert(ferr == XZFIL_ERR_BOUNDSERR);
msg_test_assert_enable(disable);
printf("\n");
display_zone_info("msg_mon_get_zone_info_detail - nid is -1, zid is -1",&zinfo);
printf("Error returned should be BOUNDSERR 22, value was %d",ferr);
ferr = msg_mon_get_zone_info_detail(cnid, -1, &zinfo1);
TEST_CHK_FEOK(ferr);
printf("\n");
printf("Opened nid is %d\n", cnid);
display_zone_info("msg_mon_get_zone_info_detail - nid is opened nid, zid is -1",&zinfo1);
printf("Previous zid was %d\n", zinfo.node[0].zid);
ferr = msg_mon_get_zone_info_detail(-1, zinfo.node[0].zid, &zinfo2);
TEST_CHK_FEOK(ferr);
display_zone_info("msg_mon_get_zone_info_detail - nid is -1, zid is previous zid",&zinfo2);
printf("\n");
sleep(20);
ferr = msg_mon_get_zone_info(&node_info_count, 0, NULL);
printf("\nmsg_mon_get_zone_info returned %d nodes\n", node_info_count);
TEST_CHK_FEOK(ferr);
node_info_max = node_info_count;
zone_info = (MS_Mon_Zone_Info_Entry_Type *)malloc(node_info_count * sizeof(MS_Mon_Zone_Info_Entry_Type));
//zone_info = (MS_Mon_Zone_Info_Type *)malloc(node_info_count * sizeof(MS_Mon_Zone_Info_Type));
ferr = msg_mon_get_zone_info(&node_info_count, node_info_max, zone_info);
TEST_CHK_FEOK(ferr);
printf("\nUsing display_info_entry\n");
display_info_entry(node_info_count, zone_info);
free(zone_info);
ferr = msg_mon_register_death_notification(cnid, cpid);
TEST_CHK_FEOK(ferr);
}
void srv_process_sm_node_down() {
srv_process_sm(MS_MsgType_NodeDown);
if (chk)
srv_process_sm_node_down_chk();
}
void srv_process_sm_node_down_all() {
enum {
SM_C = 1,
SM_ND = 2,
SM_PD = 4
};
int inx;
int sm_mask = 0;
int sm_type;
const char *str_act;
const char *str_sm_c;
const char *str_sm_nd;
const char *str_sm_pd;
bool xchk;
// close/process-death/node-down can happen in any order
xchk = chk;
chk = false;
for (inx = 0; inx < 3; inx++) {
srv_process_sm(-1);
switch (sys_msg->type) {
case MS_MsgType_Close:
sm_type = SM_C;
break;
case MS_MsgType_NodeDown:
sm_type = SM_ND;
break;
case MS_MsgType_ProcessDeath:
sm_type = SM_PD;
break;
default:
sm_type = 0;
str_sm_c = srv_sm_lookup(MS_MsgType_Close);
str_sm_nd = srv_sm_lookup(MS_MsgType_NodeDown);
str_sm_pd = srv_sm_lookup(MS_MsgType_ProcessDeath);
str_act = srv_sm_lookup(sys_msg->type);
printf("expecting msg-type=%d(%s)/%d(%s)/%d(%s), actual msg-type=%d(%s)\n",
MS_MsgType_Close, str_sm_c,
MS_MsgType_NodeDown, str_sm_nd,
MS_MsgType_ProcessDeath, str_sm_pd,
sys_msg->type, str_act);
assert((sys_msg->type == MS_MsgType_Close) ||
(sys_msg->type == MS_MsgType_NodeDown) ||
(sys_msg->type == MS_MsgType_ProcessDeath));
break;
}
assert((sm_type & sm_mask) == 0);
sm_mask |= sm_type;
if (xchk) {
switch (sys_msg->type) {
case MS_MsgType_Close:
srv_process_sm_close_chk();
break;
case MS_MsgType_NodeDown:
srv_process_sm_node_down_chk();
break;
case MS_MsgType_ProcessDeath:
srv_process_sm_process_death_chk();
break;
default:
break;
}
}
}
chk = xchk;
}
void srv_process_sm_node_down_chk() {
assert(sys_msg->u.down.nid == cnid);
assert(strcmp(sys_msg->u.down.node_name, cinfo.node[0].node_name) == 0);
}
void srv_process_sm_node_quiesce() {
srv_process_sm(MS_MsgType_NodeQuiesce);
assert(sys_msg->u.quiesce.nid == cnid);
assert(strcmp(sys_msg->u.quiesce.node_name, cinfo.node[0].node_name) == 0);
}
void srv_process_sm_node_up() {
srv_process_sm(MS_MsgType_NodeUp);
if (chk) {
assert(sys_msg->u.up.nid == cnid);
assert(strcmp(sys_msg->u.up.node_name, cinfo.node[0].node_name) == 0);
}
}
void srv_process_sm_process_created() {
srv_process_sm(MS_MsgType_ProcessCreated);
// can't check nid/pid
assert(sys_msg->u.process_created.tag == 9);
assert(strcasecmp(sys_msg->u.process_created.process_name, "$die") == 0);
assert(sys_msg->u.process_created.ferr == XZFIL_ERR_OK);
}
void srv_process_sm_process_death() {
srv_process_sm(MS_MsgType_ProcessDeath);
if (chk)
srv_process_sm_process_death_chk();
}
void srv_process_sm_process_death_chk() {
int inx;
int len;
assert(sys_msg->u.death.nid == cnid);
assert(sys_msg->u.death.pid == cpid);
len = (int) (sizeof(sys_msg->u.death.transid) /
sizeof(sys_msg->u.death.transid.id[0]));
for (inx = 0; inx < len; inx++)
assert(sys_msg->u.death.transid.id[inx] == 0);
assert(sys_msg->u.death.aborted);
assert(strcasecmp(sys_msg->u.death.process_name, "$cli") == 0);
assert(sys_msg->u.death.type == MS_ProcessType_TSE);
}
void srv_process_sm_shutdown() {
const char *str_act;
const char *str_sm_pd;
const char *str_sm_s;
bool xchk;
// there might be a process death before shutdown
xchk = chk;
chk = false;
srv_process_sm(-1);
switch (sys_msg->type) {
case MS_MsgType_ProcessDeath:
srv_process_sm(MS_MsgType_Shutdown);
break;
case MS_MsgType_Shutdown:
break;
default:
str_sm_pd = srv_sm_lookup(MS_MsgType_ProcessDeath);
str_sm_s = srv_sm_lookup(MS_MsgType_Shutdown);
str_act = srv_sm_lookup(sys_msg->type);
printf("expecting msg-type=%d(%s)/%d(%s), actual msg-type=%d(%s)\n",
MS_MsgType_ProcessDeath, str_sm_pd,
MS_MsgType_Shutdown, str_sm_s,
sys_msg->type, str_act);
assert((sys_msg->type == MS_MsgType_ProcessDeath) ||
(sys_msg->type == MS_MsgType_Shutdown));
break;
}
if (chk) {
assert(sys_msg->u.shutdown.nid == snid);
assert(sys_msg->u.shutdown.pid == -1);
assert(sys_msg->u.shutdown.level == MS_Mon_ShutdownLevel_Normal);
}
chk = xchk;
}
const char *srv_sm_lookup(int mt) {
const char *ret;
switch (mt) {
case MS_MsgType_Change: // tested
ret = "MS_MsgType_Change";
break;
case MS_MsgType_Close: // tested
ret = "MS_MsgType_Close";
break;
case MS_MsgType_Event: // impossible
ret = "MS_MsgType_Event";
break;
case MS_MsgType_NodeDown: // tested
ret = "MS_MsgType_NodeDown";
break;
case MS_MsgType_NodeQuiesce: // tested
ret = "MS_MsgType_NodeQuiesce";
break;
case MS_MsgType_NodeUp: // tested
ret = "MS_MsgType_NodeUp";
break;
case MS_MsgType_Open: // tested
ret = "MS_MsgType_Open";
break;
case MS_MsgType_ProcessCreated: // tested
ret = "MS_MsgType_ProcessCreated";
break;
case MS_MsgType_ProcessDeath: // tested
ret = "MS_MsgType_ProcessDeath";
break;
case MS_MsgType_Service: // impossible
ret = "MS_MsgType_Service";
break;
case MS_MsgType_Shutdown: // tested
ret = "MS_MsgType_Shutdown";
break;
case MS_MsgType_TmSyncAbort: // trans-test
ret = "MS_MsgType_TmSyncAbort";
break;
case MS_MsgType_TmSyncCommit: // trans-test
ret = "MS_MsgType_TmSyncCommit";
break;
case MS_MsgType_UnsolicitedMessage: // trans-test
ret = "MS_MsgType_UnsolicitedMessage";
break;
default:
ret = "?";
break;
}
return ret;
}
int main(int argc, char *argv[]) {
bool client = false;
bool die = false;
int disable;
char event_data[MS_MON_MAX_SYNC_DATA];
int event_len;
int ferr;
int len;
int msgid;
bool nochk = false;
int oid;
TPT_DECL (phandle);
RT results;
TAD zargs[] = {
{ "-client", TA_Bool, TA_NOMAX, &client },
{ "-die", TA_Bool, TA_NOMAX, &die },
{ "-nochk", TA_Bool, TA_NOMAX, &nochk },
{ "-quiesce", TA_Bool, TA_NOMAX, &quiesce },
{ "-server", TA_Ign, TA_NOMAX, NULL },
{ "-v", TA_Bool, TA_NOMAX, &verbose },
{ "", TA_End, TA_NOMAX, NULL }
};
msfs_util_init(&argc, &argv, msg_debug_hook);
gargc = argc;
gargv = argv;
arg_proc_args(zargs, false, argc, argv);
if (nochk)
chk = false;
util_test_start(client);
ferr = msg_mon_process_startup(!client); // system messages?
TEST_CHK_FEOK(ferr);
if (die) {
ferr = msg_mon_process_shutdown();
TEST_CHK_FEOK(ferr);
return 0;
}
if (client) {
ferr = msg_mon_open_process((char *) "$srv", // name
TPT_REF(phandle),
&oid);
TEST_CHK_FEOK(ferr);
strcpy(send_buffer, "control\n");
len = (int) strlen(send_buffer) + 1;
ferr = BMSG_LINK_(TPT_REF(phandle), // phandle
&msgid, // msgid
NULL, // reqctrl
0, // reqctrlsize
NULL, // replyctrl
0, // replyctrlmax
send_buffer, // reqdata
len, // reqdatasize
recv_buffer, // replydata
40000, // replydatamax
0, // linkertag
0, // pri
0, // xmitclass
0); // linkopts
util_check("BMSG_LINK_", ferr);
ferr = BMSG_BREAK_(msgid, results.u.s, TPT_REF(phandle));
util_check("BMSG_BREAK_", ferr);
disable = msg_test_assert_disable();
if (quiesce) {
// just exit on a node quiesce
srv_process_sm_node_quiesce();
} else {
// wait, but the node will be downed before finishing
ferr = msg_mon_event_wait(2, &event_len, event_data);
msg_test_assert_enable(disable);
}
} else {
ferr = msg_mon_get_process_info(NULL, &snid, &spid);
TEST_CHK_FEOK(ferr);
msg_mon_enable_mon_messages(true);
srv_process_sm_open();
srv_process_sm(0);
srv_process_sm_close();
if (quiesce) {
//sleep(4);
srv_process_sm_node_quiesce();
srv_process_sm_process_death();
} else {
srv_process_sm_process_death();
srv_process_sm_node_down();
}
if (getenv("SQ_VIRTUAL_NODES") != NULL)
srv_process_sm_node_up();
srv_do_change();
srv_process_sm_change();
srv_do_start();
srv_process_sm_process_created();
srv_do_shutdown();
srv_process_sm_shutdown();
}
if (client && !quiesce) {
ferr = msg_mon_close_process(TPT_REF(phandle));
TEST_CHK_FEOK(ferr);
}
ferr = msg_mon_process_shutdown();
TEST_CHK_FEOK(ferr);
util_test_finish(!client);
return 0;
}