diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 1b0f0e6b7..387c4191b 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -21,7 +21,8 @@ __Add new items below here__ ### New `dbServerStats()` API for iocStats A new routine provides the ability to request channel and client counts from -name server layers that implement the `stats()` method. A preprocessor macro +named server layers that implement the `stats()` method, or to get a summary +of the counts from all registered server layers. A preprocessor macro `HAS_DBSERVER_STATS` macro is defined in the `dbServer.h` header file to simplify code that needs to support older versions of Base as well. diff --git a/modules/database/src/ioc/db/dbServer.c b/modules/database/src/ioc/db/dbServer.c index f08eec828..c4e5f55c3 100644 --- a/modules/database/src/ioc/db/dbServer.c +++ b/modules/database/src/ioc/db/dbServer.c @@ -130,11 +130,23 @@ int dbServerClient(char *pBuf, size_t bufSize) int dbServerStats(const char *name, unsigned *channels, unsigned *clients) { dbServer *psrv = (dbServer *)ellFirst(&serverList); + unsigned tch, tcl; - if (!name || state != running || !psrv) + if (state != running || !psrv) return -1; - while (psrv) { + for (tch = 0, tcl = 0; psrv; + psrv = (dbServer *)ellNext(&psrv->node)) { + if (!name) { + if (psrv->stats) { + unsigned lch, lcl; + + psrv->stats(&lch, &lcl); + tch += lch; + tcl += lcl; + } + continue; + } if (strcmp(name, psrv->name) == 0) { if (!psrv->stats) return -1; @@ -142,7 +154,11 @@ int dbServerStats(const char *name, unsigned *channels, unsigned *clients) psrv->stats(channels, clients); return 0; } - psrv = (dbServer *)ellNext(&psrv->node); + } + if (!name) { + if (channels) *channels = tch; + if (clients) *clients = tcl; + return 0; } return -1; } diff --git a/modules/database/src/ioc/db/dbServer.h b/modules/database/src/ioc/db/dbServer.h index 86c3f7d82..9b16c3b3d 100644 --- a/modules/database/src/ioc/db/dbServer.h +++ b/modules/database/src/ioc/db/dbServer.h @@ -151,9 +151,11 @@ DBCORE_API int dbServerClient(char *pBuf, size_t bufSize); * * This is an API for iocStats and similar to fetch the number of channels * and clients connected to the named server layer. + * If the name given is NULL the statistics returned are the totals for + * all the registered server layers. * @param name Server name - * @param channels Where to return the channel count - * @param clients Where to return the client count + * @param channels NULL, or where to return the channel count + * @param clients NULL or where to return the client count * @returns 0 on success; -1 if IOC isn't running, no such named server, * or that server doesn't implement the stats method. * diff --git a/modules/database/test/ioc/db/dbServerTest.c b/modules/database/test/ioc/db/dbServerTest.c index 9379d9fb1..97e547deb 100644 --- a/modules/database/test/ioc/db/dbServerTest.c +++ b/modules/database/test/ioc/db/dbServerTest.c @@ -40,8 +40,8 @@ void oneReport(unsigned level) void oneStats(unsigned *channels, unsigned *clients) { oneState = STATS_CALLED; - *channels = 2; - *clients = 1; + if (channels) *channels = 2; + if (clients) *clients = 1; } int oneClient(char *pbuf, size_t len) @@ -132,7 +132,7 @@ MAIN(dbServerTest) int status; unsigned ch=0, cl=0; - testPlan(29); + testPlan(32); /* Prove that we handle substring names properly */ epicsEnvSet("EPICS_IOC_IGNORE_SERVERS", "none ones"); @@ -167,12 +167,22 @@ MAIN(dbServerTest) testDiag("Checking server methods called"); dbsr(0); testOk(oneState == REPORT_CALLED, "dbsr called one::report()"); + + testDiag("Checking stats functionality"); testOk(dbServerStats("none", &ch, &cl) != 0, "Stats: unknown name rejected"); testOk(dbServerStats("no-routines", &ch, &cl) != 0, "Stats: no-routine rejected"); testOk(dbServerStats("one", &ch, &cl) == 0 && oneState == STATS_CALLED, "dbServerStats('one') called one::stats()"); - testOk(ch == 2 && cl == 1, "Stats: counts returned as expected"); + testOk(ch == 2 && cl == 1, "Stats: ch==%d, cl==%d (expected 2, 1)", ch, cl); + ch = 10; cl = 10; oneState = NOTHING_CALLED; + testOk(dbServerStats(NULL, NULL, &cl) == 0 && oneState == STATS_CALLED, + "dbServerStats(NULL, &cl) called one::stats()"); + testOk(dbServerStats(NULL, &ch, NULL) == 0 && oneState == STATS_CALLED, + "dbServerStats(NULL, &ch) called one::stats()"); + testOk(ch == 2 && cl == 1, "Stats: ch==%d, cl==%d (expected 2, 1)", ch, cl); + + testDiag("Checking client identification"); oneSim = NULL; name[0] = 0; status = dbServerClient(name, sizeof(name));