Add DynamicStats (#7704)
diff --git a/.gitignore b/.gitignore
index 64feec8..849f3ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -90,6 +90,7 @@
src/tscore/test_tscore
src/tscpp/util/test_tscpputil
lib/records/test_librecords
+lib/records/test_librecords_on_eventsystem
lib/perl/lib/Apache/TS.pm
iocore/net/test_certlookup
diff --git a/lib/records/DynamicStats.h b/lib/records/DynamicStats.h
new file mode 100644
index 0000000..d31c71f
--- /dev/null
+++ b/lib/records/DynamicStats.h
@@ -0,0 +1,170 @@
+/** @file
+
+ Dynamic Stats
+
+ @section license License
+
+ 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.
+ */
+
+#pragma once
+
+#include "records/I_RecCore.h"
+#include "records/I_RecDefs.h"
+#include "records/I_RecProcess.h"
+
+/**
+ @class DynamicStats
+ @details
+ core version of TSStat* APIs
+
+ - supported: TSStatCreate, TSStatIntIncrement/TSStatIntDecrement, TSStatIntGet, TSStatIntSet, TSStatFindName
+
+ CAVEAT: The librecords doesn't have APIs for "unregister stats" or "realloc rsb".
+ If you want to register ton of stats, bump -maxRecords option of traffic_manager/traffic_server.
+
+ */
+class DynamicStats
+{
+public:
+ // Modifiers
+ void init(int max_stats);
+ int create(RecT rec_type, const char *name, RecDataT data_type, RecRawStatSyncCb sync_cb, bool is_persistent = false);
+ int increment(int id, int64_t amount);
+ int set_sum(int id, int64_t value);
+
+ // References
+ int64_t get_sum(int id) const;
+ int find(const char *name) const;
+ bool is_allocated() const;
+
+private:
+ RecRawStatBlock *_rsb = nullptr;
+ std::atomic<int> _rsb_index = 0;
+};
+
+////
+// Inline functions
+//
+inline void
+DynamicStats::init(int max_stats)
+{
+ _rsb = RecAllocateRawStatBlock(max_stats);
+}
+
+/**
+ TSStatCreate
+ */
+inline int
+DynamicStats::create(RecT rec_type, const char *name, RecDataT data_type, RecRawStatSyncCb sync_cb, bool is_persistent)
+{
+ if (name == nullptr || _rsb_index >= _rsb->max_stats) {
+ return REC_ERR_FAIL;
+ }
+
+ int stat_id = _rsb_index;
+
+ if (is_persistent) {
+ int r = RecRegisterRawStat(_rsb, rec_type, name, data_type, RECP_PERSISTENT, stat_id, sync_cb);
+ if (r != REC_ERR_OKAY) {
+ return REC_ERR_FAIL;
+ }
+ } else {
+ int r = RecRegisterRawStat(_rsb, rec_type, name, data_type, RECP_NON_PERSISTENT, stat_id, sync_cb);
+ if (r != REC_ERR_OKAY) {
+ return REC_ERR_FAIL;
+ }
+ }
+
+ RecSetRawStatSum(_rsb, stat_id, 0);
+ RecSetRawStatCount(_rsb, stat_id, 0);
+
+ _rsb_index++;
+
+ return stat_id;
+}
+
+/**
+ TSStatIntIncrement / TSStatIntDecrement
+ */
+inline int
+DynamicStats::increment(int id, int64_t amount)
+{
+ if (id < 0) {
+ return REC_ERR_FAIL;
+ }
+
+ return RecIncrRawStat(_rsb, nullptr, id, amount);
+}
+
+/**
+ TSStatIntSet
+ */
+inline int
+DynamicStats::set_sum(int id, int64_t value)
+{
+ if (id < 0) {
+ return REC_ERR_FAIL;
+ }
+
+ return RecSetGlobalRawStatSum(_rsb, id, value);
+}
+
+/**
+ TSStatIntGet
+ */
+inline int64_t
+DynamicStats::get_sum(int id) const
+{
+ int64_t value = -1;
+
+ if (id < 0) {
+ return value;
+ }
+
+ RecGetGlobalRawStatSum(_rsb, id, &value);
+
+ return value;
+}
+
+/**
+ TSStatFindName
+ */
+inline int
+DynamicStats::find(const char *name) const
+{
+ if (name == nullptr) {
+ return REC_ERR_FAIL;
+ }
+
+ int id;
+ if (RecGetRecordOrderAndId(name, nullptr, &id, true, true) != REC_ERR_OKAY) {
+ return REC_ERR_FAIL;
+ }
+
+ if (RecGetGlobalRawStatPtr(_rsb, id) == nullptr) {
+ return REC_ERR_FAIL;
+ }
+
+ return id;
+}
+
+inline bool
+DynamicStats::is_allocated() const
+{
+ return _rsb != nullptr;
+}
diff --git a/lib/records/Makefile.am b/lib/records/Makefile.am
index 8fc83fb..2dd0ca5 100644
--- a/lib/records/Makefile.am
+++ b/lib/records/Makefile.am
@@ -18,7 +18,7 @@
include $(top_srcdir)/build/tidy.mk
-check_PROGRAMS = test_librecords
+check_PROGRAMS = test_librecords test_librecords_on_eventsystem
AM_CPPFLAGS += \
-I$(abs_top_srcdir)/iocore/eventsystem \
@@ -71,7 +71,7 @@
TESTS = $(check_PROGRAMS)
test_librecords_CPPFLAGS = $(AM_CPPFLAGS)\
- -I$(abs_top_srcdir)/tests/include
+ -I$(abs_top_srcdir)/tests/include
test_librecords_SOURCES = \
unit_tests/unit_test_main.cc \
@@ -86,6 +86,21 @@
$(top_builddir)/proxy/shared/libUglyLogStubs.a \
@HWLOC_LIBS@ @LIBCAP@
+test_librecords_on_eventsystem_CPPFLAGS = $(AM_CPPFLAGS)\
+ -I$(abs_top_srcdir)/tests/include
+
+test_librecords_on_eventsystem_SOURCES = \
+ unit_tests/unit_test_main_on_eventsystem.cc \
+ unit_tests/test_DynamicStats.cc
+
+test_librecords_on_eventsystem_LDADD = \
+ $(top_builddir)/lib/records/librecords_p.a \
+ $(top_builddir)/mgmt/libmgmt_p.la \
+ $(top_builddir)/iocore/eventsystem/libinkevent.a \
+ $(top_builddir)/src/tscpp/util/libtscpputil.la \
+ $(top_builddir)/src/tscore/libtscore.la \
+ $(top_builddir)/proxy/shared/libUglyLogStubs.a \
+ @HWLOC_LIBS@ @LIBCAP@
clang-tidy-local: $(sort $(DIST_SOURCES))
$(CXX_Clang_Tidy)
diff --git a/lib/records/unit_tests/test_DynamicStats.cc b/lib/records/unit_tests/test_DynamicStats.cc
new file mode 100644
index 0000000..7eef407
--- /dev/null
+++ b/lib/records/unit_tests/test_DynamicStats.cc
@@ -0,0 +1,47 @@
+/** @file
+
+ Unit tests for BufferWriter.h.
+
+ @section license License
+
+ 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.
+ */
+
+#include "catch.hpp"
+
+#include "DynamicStats.h"
+#include "P_RecProcess.h"
+
+#include <string_view>
+
+TEST_CASE("DynamicStats", "[DynamicStats]")
+{
+ SECTION("set/get_sum")
+ {
+ DynamicStats stats;
+ stats.init(10);
+ REQUIRE(stats.is_allocated() == true);
+
+ std::string_view name = "proxy.process.test.dynamic.stats";
+ int id = stats.create(RECT_PROCESS, name.data(), RECD_INT, RecRawStatSyncSum);
+ REQUIRE(id == 0);
+ CHECK(id == stats.find(name.data()));
+
+ CHECK(stats.set_sum(id, 12345) == REC_ERR_OKAY);
+ CHECK(stats.get_sum(id) == 12345);
+ }
+}
diff --git a/lib/records/unit_tests/unit_test_main_on_eventsystem.cc b/lib/records/unit_tests/unit_test_main_on_eventsystem.cc
new file mode 100644
index 0000000..1df1d98
--- /dev/null
+++ b/lib/records/unit_tests/unit_test_main_on_eventsystem.cc
@@ -0,0 +1,56 @@
+/** @file
+
+ Catch based unit tests on EventSystem
+
+ @section license License
+
+ 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.
+ */
+
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include "I_EventSystem.h"
+#include "tscore/I_Layout.h"
+#include "tscore/TSSystemState.h"
+
+#include "diags.i"
+
+namespace
+{
+constexpr int TEST_THREADS = 2;
+}
+
+struct EventProcessorListener : Catch::TestEventListenerBase {
+ using TestEventListenerBase::TestEventListenerBase;
+
+ void
+ testRunStarting(Catch::TestRunInfo const &testRunInfo) override
+ {
+ Layout::create();
+ init_diags("", nullptr);
+ RecProcessInit(RECM_STAND_ALONE);
+
+ ink_event_system_init(EVENT_SYSTEM_MODULE_PUBLIC_VERSION);
+ eventProcessor.start(TEST_THREADS);
+
+ EThread *main_thread = new EThread;
+ main_thread->set_specific();
+ }
+};
+
+CATCH_REGISTER_LISTENER(EventProcessorListener);