ubik: Introduce ubik_CallRock 87/13987/15
authorAndrew Deason <adeason@sinenomine.net>
Fri, 23 Aug 2019 17:21:54 +0000 (12:21 -0500)
committerBenjamin Kaduk <kaduk@mit.edu>
Fri, 13 Mar 2020 03:49:45 +0000 (23:49 -0400)
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 <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/libafsauthent/afsauthent.def
src/libafsauthent/libafsauthent.la.sym
src/rxgen/rpc_parse.c
src/ubik/ubik.p.h
src/ubik/ubikclient.c

index 10c71cb..02c4825 100644 (file)
@@ -210,3 +210,4 @@ EXPORTS
         xdr_namelist                                   @209
         xdr_prlist                                     @210
         afsconf_CountKeys                              @211
+        ubik_CallRock                                  @212
index 83aa04e..c8a9bae 100644 (file)
@@ -120,6 +120,7 @@ token_setPag
 token_setRxkadViceId
 ubik_Call
 ubik_CallIter
+ubik_CallRock
 ubik_Call_New
 ubik_ClientDestroy
 ubik_ClientInit
index 768e42f..668ce94 100644 (file)
@@ -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");
 }
 
 
index fe81862..2c3371f 100644 (file)
@@ -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,
index 450b153..186c620 100644 (file)
@@ -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;
+}