From: Andrew Deason Date: Fri, 23 Aug 2019 17:21:54 +0000 (-0500) Subject: ubik: Introduce ubik_CallRock X-Git-Tag: openafs-devel-1_9_0~137 X-Git-Url: http://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=091e8e9ca52e408c52e3310588d6c959a517a15c ubik: Introduce ubik_CallRock In OpenAFS 1.0, the way we made dbserver RPC calls was to pass the relevant RPC and arguments to ubik_Call()/ubik_Call_New(), which coerced all of the RPC arguments into 'long's. To make this more typesafe, in commit 4478d3a9 (ubik-call-sucks-20060703) most callers were converted to use ubik_RPC_name()-style calls, which used functions autogenerated by rxgen. This latter approach, however, only lets us use the ubik_Call-style site selection code with RPCs processed by rxgen; we can't insert additional code to run before or after the relevant RPC. To make our dbserver calls more flexible, but avoid coercing all of our arguments into 'long's again, move back to the ubik_Call()-style approach, but use actual typed arguments with a callback function and a rock. Call it ubik_CallRock(). With this commit rxgen still generates the ubik_RPC_name()-style stubs, but the stubs just call ubik_CallRock with a generated callback function, instead of spitting out the equivalent of ubik_Call() in the generated code itself. To try to ensure that this commit doesn't incur any unintended extra changes, make ubik_CallRock consist of the generated code that was inside rxgen before this commit. This is almost identical to ubik_Call, but not quite; consolidating these two functions can happen in a future commit if desired. Change-Id: I0c3936e67a40e311bff32110b2c80696414b52d4 Reviewed-on: https://gerrit.openafs.org/13987 Tested-by: BuildBot Reviewed-by: Benjamin Kaduk --- diff --git a/src/libafsauthent/afsauthent.def b/src/libafsauthent/afsauthent.def index 10c71cb..02c4825 100644 --- a/src/libafsauthent/afsauthent.def +++ b/src/libafsauthent/afsauthent.def @@ -210,3 +210,4 @@ EXPORTS xdr_namelist @209 xdr_prlist @210 afsconf_CountKeys @211 + ubik_CallRock @212 diff --git a/src/libafsauthent/libafsauthent.la.sym b/src/libafsauthent/libafsauthent.la.sym index 83aa04e..c8a9bae 100644 --- a/src/libafsauthent/libafsauthent.la.sym +++ b/src/libafsauthent/libafsauthent.la.sym @@ -120,6 +120,7 @@ token_setPag token_setRxkadViceId ubik_Call ubik_CallIter +ubik_CallRock ubik_Call_New ubik_ClientDestroy ubik_ClientInit diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c index 768e42f..668ce94 100644 --- a/src/rxgen/rpc_parse.c +++ b/src/rxgen/rpc_parse.c @@ -125,10 +125,12 @@ static void cs_ProcMarshallInParams_setup(definition * defp, int split_flag); static void cs_ProcSendPacket_setup(definition * defp, int split_flag); static void cs_ProcUnmarshallOutParams_setup(definition * defp); static void cs_ProcTail_setup(definition * defp, int split_flag); +static void ucs_ProcCallback_setup(definition * defp, char *cbheader); static void ucs_ProcName_setup(definition * defp, char *procheader, int split_flag); static void ucs_ProcParams_setup(definition * defp, int split_flag); -static void ucs_ProcTail_setup(definition * defp, int split_flag); +static void ucs_ProcTail_setup(definition * defp, char *cbheader, + int split_flag); static void ss_Proc_CodeGeneration(definition * defp); static void ss_ProcName_setup(definition * defp); static void ss_ProcParams_setup(definition * defp); @@ -1060,10 +1062,13 @@ cs_Proc_CodeGeneration(definition * defp, int split_flag, char *procheader) } if (!kflag && !split_flag && uflag) { + if (!cflag) { + ucs_ProcCallback_setup(defp, "ubik_call_"); + } ucs_ProcName_setup(defp, "ubik_", split_flag); if (!cflag) { ucs_ProcParams_setup(defp, split_flag); - ucs_ProcTail_setup(defp, split_flag); + ucs_ProcTail_setup(defp, "ubik_call_", split_flag); } } } @@ -1672,6 +1677,68 @@ ss_ProcTail_setup(definition * defp) f_print(fout, "}\n\n"); } +static void +ucs_ProcCallback_setup(definition * defp, char *cbheader) +{ + proc1_list *plist; + int any_params = 0; + + for (plist = defp->pc.plists; plist; plist = plist->next) { + if (plist->component_kind == DEF_PARAM) { + any_params = 1; + break; + } + } + + if (any_params) { + f_print(fout, "struct args_%s%s%s {\n", prefix, + PackagePrefix[PackageIndex], defp->pc.proc_name); + + for (plist = defp->pc.plists; plist; plist = plist->next) { + if (plist->component_kind == DEF_PARAM) { + f_print(fout, "\t"); + if (plist->pl.param_kind == DEF_INPARAM && + strcmp(plist->pl.param_type, "char *") == 0) { + f_print(fout, "const "); + } + if ((plist->pl.param_flag & OUT_STRING) != 0) { + f_print(fout, "%s *%s", plist->pl.param_type, + plist->pl.param_name); + } else { + f_print(fout, "%s %s", plist->pl.param_type, + plist->pl.param_name); + } + f_print(fout, ";\n"); + } + } + + f_print(fout, "};\n"); + } + + f_print(fout, "static int\n" + "%s%s%s%s(struct ubik_callrock_info *info, void *z_rock)\n" + "{\n", + cbheader, prefix, PackagePrefix[PackageIndex], + defp->pc.proc_name); + + if (any_params) { + f_print(fout, "\tstruct args_%s%s%s *z_args = z_rock;\n", prefix, + PackagePrefix[PackageIndex], defp->pc.proc_name); + } + + f_print(fout, "\treturn %s%s%s(info->conn", prefix, PackagePrefix[PackageIndex], + defp->pc.proc_name); + + for (plist = defp->pc.plists; plist; plist = plist->next) { + if (plist->component_kind == DEF_PARAM) { + f_print(fout, ",\n\t\t\tz_args->%s", plist->pl.param_name); + } + } + + f_print(fout, ");\n" + "}\n"); + +} static void ucs_ProcName_setup(definition * defp, char *procheader, int split_flag) @@ -1762,115 +1829,41 @@ ucs_ProcParams_setup(definition * defp, int split_flag) } static void -ucs_ProcTail_setup(definition * defp, int split_flag) +ucs_ProcTail_setup(definition * defp, char *cbheader, int split_flag) { proc1_list *plist; + int any_params = 0; + + f_print(fout, "{\n"); - f_print(fout, "{\tafs_int32 rcode, code, newHost, thisHost, i, _ucount;\n"); - f_print(fout, "\tint chaseCount, pass, needsync;\n"); - f_print(fout, "\tstruct rx_connection *tc;\n"); - f_print(fout, "\tstruct rx_peer *rxp;\n"); - f_print(fout, "\tshort origLevel;\n\n"); - f_print(fout, "\tif (!aclient)\n"); - f_print(fout, "\t\treturn UNOENT;\n"); - f_print(fout, "\tLOCK_UBIK_CLIENT(aclient);\n\n"); - f_print(fout, "\t restart:\n"); - f_print(fout, "\torigLevel = aclient->initializationState;\n"); - f_print(fout, "\trcode = UNOSERVERS;\n"); - f_print(fout, "\tchaseCount = needsync = 0;\n\n"); - f_print(fout, "\t/* \n\t* First pass, we try all servers that are up.\n\t* Second pass, we try all servers.\n\t*/\n"); - f_print(fout, "\tfor (pass = 0; pass < 2; pass++) { /*p */\n"); - f_print(fout, "\t\t/* For each entry in our servers list */\n"); - f_print(fout, "\t\tfor (_ucount = 0;; _ucount++) { /*s */\n\n"); - f_print(fout, "\t\tif (needsync) {\n"); - f_print(fout, "\t\t\t/* Need a sync site. Lets try to quickly find it */\n"); - f_print(fout, "\t\t\tif (aclient->syncSite) {\n"); - f_print(fout, "\t\t\t\tnewHost = aclient->syncSite; /* already in network order */\n"); - f_print(fout, "\t\t\t\taclient->syncSite = 0; /* Will reset if it works */\n"); - f_print(fout, "\t\t\t} else if (aclient->conns[3]) {\n"); - f_print(fout, "\t\t\t\t/* If there are fewer than four db servers in a cell,\n"); - f_print(fout, "\t\t\t\t* there's no point in making the GetSyncSite call.\n"); - f_print(fout, "\t\t\t\t* At best, it's a wash. At worst, it results in more\n"); - f_print(fout, "\t\t\t\t* RPCs than you would otherwise make.\n"); - f_print(fout, "\t\t\t\t*/\n"); - f_print(fout, "\t\t\t\ttc = aclient->conns[_ucount];\n"); - f_print(fout, "\t\t\t\tif (tc && rx_ConnError(tc)) {\n"); - f_print(fout, "\t\t\t\t\taclient->conns[_ucount] = tc = ubik_RefreshConn(tc);\n"); - f_print(fout, "\t\t\t\t}\n"); - f_print(fout, "\t\t\t\tif (!tc)\n"); - f_print(fout, "\t\t\t\t\tbreak;\n"); - f_print(fout, "\t\t\t\tcode = VOTE_GetSyncSite(tc, &newHost);\n"); - f_print(fout, "\t\t\t\tif (aclient->initializationState != origLevel)\n"); - f_print(fout, "\t\t\t\t\tgoto restart; /* somebody did a ubik_ClientInit */\n"); - f_print(fout, "\t\t\t\tif (code)\n"); - f_print(fout, "\t\t\t\t\tnewHost = 0;\n"); - f_print(fout, "\t\t\t\tnewHost = htonl(newHost); /* convert to network order */\n"); - f_print(fout, "\t\t\t} else {\n"); - f_print(fout, "\t\t\t\tnewHost = 0;\n"); - f_print(fout, "\t\t\t}\n"); - f_print(fout, "\t\t\tif (newHost) {\n"); - f_print(fout, "\t\t\t\t/* position count at the appropriate slot in the client\n"); - f_print(fout, "\t\t\t\t* structure and retry. If we can't find in slot, we'll\n"); - f_print(fout, "\t\t\t\t* just continue through the whole list \n"); - f_print(fout, "\t\t\t\t*/\n"); - f_print(fout, "\t\t\t\tfor (i = 0; i < MAXSERVERS && aclient->conns[i]; i++) {\n"); - f_print(fout, "\t\t\t\t\trxp = rx_PeerOf(aclient->conns[i]);\n"); - f_print(fout, "\t\t\t\t\tthisHost = rx_HostOf(rxp);\n"); - f_print(fout, "\t\t\t\t\tif (!thisHost)\n"); - f_print(fout, "\t\t\t\t\t\tbreak;\n"); - f_print(fout, "\t\t\t\t\tif (thisHost == newHost) {\n"); - f_print(fout, "\t\t\t\t\t\tif (chaseCount++ > 2)\n"); - f_print(fout, "\t\t\t\t\t\t\tbreak; /* avoid loop asking */\n"); - f_print(fout, "\t\t\t\t\t\t_ucount = i; /* this index is the sync site */\n"); - f_print(fout, "\t\t\t\t\t\tbreak;\n"); - f_print(fout, "\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n"); - f_print(fout, "\t\t/*needsync */\n"); - f_print(fout, "\t\ttc = aclient->conns[_ucount];\n"); - f_print(fout, "\t\tif (tc && rx_ConnError(tc)) {\n"); - f_print(fout, "\t\t\taclient->conns[_ucount] = tc = ubik_RefreshConn(tc);\n"); - f_print(fout, "\t\t}\n"); - f_print(fout, "\t\tif (!tc)\n"); - f_print(fout, "\t\t\tbreak;\n\n"); - f_print(fout, "\t\tif ((pass == 0) && (aclient->states[_ucount] & CFLastFailed)) {\n"); - f_print(fout, "\t\t\tcontinue; /* this guy's down */\n"); - f_print(fout, "\t\t}\n"); - - f_print(fout, "\t\trcode = %s%s%s(tc\n", prefix, PackagePrefix[PackageIndex], defp->pc.proc_name); for (plist = defp->pc.plists; plist; plist = plist->next) { if (plist->component_kind == DEF_PARAM) { - plist->pl.param_flag &= ~PROCESSED_PARAM; - f_print(fout, ", %s", plist->pl.param_name); + any_params = 1; + break; } } - f_print(fout, ");\n"); - f_print(fout, "\t\tif (aclient->initializationState != origLevel) {\n"); - f_print(fout, "\t\t\t/* somebody did a ubik_ClientInit */\n"); - f_print(fout, "\t\t\tif (rcode)\n"); - f_print(fout, "\t\t\t\tgoto restart; /* call failed */\n"); - f_print(fout, "\t\t\telse\n"); - f_print(fout, "\t\t\t\tgoto done; /* call suceeded */\n"); - f_print(fout, "\t\t}\n"); - f_print(fout, "\t\tif (rcode < 0) { /* network errors */\n"); - f_print(fout, "\t\t\taclient->states[_ucount] |= CFLastFailed; /* Mark server down */\n"); - f_print(fout, "\t\t} else if (rcode == UNOTSYNC) {\n"); - f_print(fout, "\t\t\tneedsync = 1;\n"); - f_print(fout, "\t\t} else if (rcode != UNOQUORUM) {\n"); - f_print(fout, "\t\t\t/* either misc ubik code, or misc appl code, or success. */\n"); - f_print(fout, "\t\t\taclient->states[_ucount] &= ~CFLastFailed; /* mark server up*/\n"); - f_print(fout, "\t\t\tgoto done; /* all done */\n"); - f_print(fout, "\t\t}\n"); - f_print(fout, "\t\t} /*s */\n"); - f_print(fout, "\t} /*p */\n\n"); - f_print(fout, "\tdone:\n"); - f_print(fout, "\tif (needsync) {\n"); - - f_print(fout, "\t\tif (!rcode) { /* Remember the sync site - cmd successful */\n"); - f_print(fout, "\t\t\trxp = rx_PeerOf(aclient->conns[_ucount]);\n"); - f_print(fout, "\t\t\taclient->syncSite = rx_HostOf(rxp);\n"); - f_print(fout, "\t\t}\n"); - f_print(fout, "\t}\n"); - f_print(fout, "\tUNLOCK_UBIK_CLIENT(aclient);\n"); - f_print(fout, "\treturn rcode;\n}\n\n"); + + if (any_params) { + f_print(fout, "\tstruct args_%s%s%s args;\n", prefix, + PackagePrefix[PackageIndex], defp->pc.proc_name); + f_print(fout, "\tmemset(&args, 0, sizeof(args));\n\n"); + + for (plist = defp->pc.plists; plist; plist = plist->next) { + if (plist->component_kind == DEF_PARAM) { + plist->pl.param_flag &= ~PROCESSED_PARAM; + f_print(fout, "\targs.%s = %s;\n", plist->pl.param_name, + plist->pl.param_name); + } + } + + f_print(fout, "\n\treturn ubik_CallRock(aclient, aflags, %s%s%s%s, &args);\n", + cbheader, prefix, PackagePrefix[PackageIndex], defp->pc.proc_name); + } else { + f_print(fout, "\treturn ubik_CallRock(aclient, aflags, %s%s%s%s, NULL);\n", + cbheader, prefix, PackagePrefix[PackageIndex], defp->pc.proc_name); + } + + f_print(fout, "}\n\n"); } diff --git a/src/ubik/ubik.p.h b/src/ubik/ubik.p.h index fe81862..2c3371f 100644 --- a/src/ubik/ubik.p.h +++ b/src/ubik/ubik.p.h @@ -585,6 +585,15 @@ extern int ubik_ClientInit(struct rx_connection **serverconns, struct ubik_client **aclient); extern afs_int32 ubik_ClientDestroy(struct ubik_client *aclient); extern struct rx_connection *ubik_RefreshConn(struct rx_connection *tc); + +struct ubik_callrock_info { + struct rx_connection *conn; +}; +typedef afs_int32 (*ubik_callrock_func)(struct ubik_callrock_info *info, void *rock); +extern afs_int32 ubik_CallRock(struct ubik_client *aclient, afs_int32 aflags, + ubik_callrock_func proc, void *rock) + AFS_NONNULL((3)); + #ifdef UBIK_LEGACY_CALLITER extern afs_int32 ubik_CallIter(int (*aproc) (), struct ubik_client *aclient, afs_int32 aflags, int *apos, long p1, long p2, diff --git a/src/ubik/ubikclient.c b/src/ubik/ubikclient.c index 450b153..186c620 100644 --- a/src/ubik/ubikclient.c +++ b/src/ubik/ubikclient.c @@ -688,3 +688,123 @@ ubik_Call(int (*aproc) (), struct ubik_client *aclient, UNLOCK_UBIK_CLIENT(aclient); return rcode; } + +afs_int32 +ubik_CallRock(struct ubik_client *aclient, afs_int32 aflags, + ubik_callrock_func proc, void *rock) +{ + afs_int32 rcode, code, newHost, thisHost, i, _ucount; + int chaseCount, pass, needsync; + struct rx_connection *tc; + struct rx_peer *rxp; + short origLevel; + + if (!aclient) + return UNOENT; + LOCK_UBIK_CLIENT(aclient); + + restart: + origLevel = aclient->initializationState; + rcode = UNOSERVERS; + chaseCount = needsync = 0; + + /* + * First pass, we try all servers that are up. + * Second pass, we try all servers. + */ + for (pass = 0; pass < 2; pass++) { + /* For each entry in our servers list */ + for (_ucount = 0;; _ucount++) { + struct ubik_callrock_info info; + if (needsync) { + /* Need a sync site. Lets try to quickly find it */ + if (aclient->syncSite) { + newHost = aclient->syncSite; /* already in network order */ + aclient->syncSite = 0; /* Will reset if it works */ + } else if (aclient->conns[3]) { + /* + * If there are fewer than four db servers in a cell, + * there's no point in making the GetSyncSite call. + * At best, it's a wash. At worst, it results in more + * RPCs than you would otherwise make. + */ + tc = aclient->conns[_ucount]; + if (tc && rx_ConnError(tc)) { + aclient->conns[_ucount] = tc = ubik_RefreshConn(tc); + } + if (!tc) + break; + code = VOTE_GetSyncSite(tc, &newHost); + if (aclient->initializationState != origLevel) + goto restart; /* somebody did a ubik_ClientInit */ + if (code) + newHost = 0; + newHost = htonl(newHost); /* convert to network order */ + } else { + newHost = 0; + } + if (newHost) { + /* + * position count at the appropriate slot in the client + * structure and retry. If we can't find in slot, we'll + * just continue through the whole list + */ + for (i = 0; i < MAXSERVERS && aclient->conns[i]; i++) { + rxp = rx_PeerOf(aclient->conns[i]); + thisHost = rx_HostOf(rxp); + if (!thisHost) + break; + if (thisHost == newHost) { + if (chaseCount++ > 2) + break; /* avoid loop asking */ + _ucount = i; /* this index is the sync site */ + break; + } + } + } + } + /*needsync */ + tc = aclient->conns[_ucount]; + if (tc && rx_ConnError(tc)) { + aclient->conns[_ucount] = tc = ubik_RefreshConn(tc); + } + if (!tc) + break; + + if ((pass == 0) && (aclient->states[_ucount] & CFLastFailed)) { + continue; /* this guy's down */ + } + + memset(&info, 0, sizeof(info)); + info.conn = tc; + rcode = (*proc)(&info, rock); + + if (aclient->initializationState != origLevel) { + /* somebody did a ubik_ClientInit */ + if (rcode) + goto restart; /* call failed */ + else + goto done; /* call suceeded */ + } + if (rcode < 0) { /* network errors */ + aclient->states[_ucount] |= CFLastFailed; /* Mark server down */ + } else if (rcode == UNOTSYNC) { + needsync = 1; + } else if (rcode != UNOQUORUM) { + /* either misc ubik code, or misc appl code, or success. */ + aclient->states[_ucount] &= ~CFLastFailed; /* mark server up*/ + goto done; /* all done */ + } + } + } + + done: + if (needsync) { + if (!rcode) { /* Remember the sync site - cmd successful */ + rxp = rx_PeerOf(aclient->conns[_ucount]); + aclient->syncSite = rx_HostOf(rxp); + } + } + UNLOCK_UBIK_CLIENT(aclient); + return rcode; +}