diff --git a/.gitignore b/.gitignore index 64feec809c8..849f3ef9a2a 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,7 @@ src/tscore/test_X509HostnameValidator 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 00000000000..d31c71f33f5 --- /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 _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 8fc83fb2f95..2dd0ca5304e 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 @@ librecords_p_a_SOURCES = \ 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 @@ test_librecords_LDADD = \ $(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 00000000000..7eef4070eb8 --- /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 + +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 00000000000..1df1d9863c0 --- /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);