-
Notifications
You must be signed in to change notification settings - Fork 112
Expand file tree
/
Copy pathconfdata-functions.cpp
More file actions
153 lines (127 loc) · 6.22 KB
/
confdata-functions.cpp
File metadata and controls
153 lines (127 loc) · 6.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Compiler for PHP (aka KPHP)
// Copyright (c) 2024 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt
#include "runtime-light/stdlib/confdata/confdata-functions.h"
#include <algorithm>
#include <cstddef>
#include <memory>
#include <span>
#include <string_view>
#include <utility>
#include "common/containers/final_action.h"
#include "runtime-common/core/allocator/script-allocator.h"
#include "runtime-common/core/runtime-core.h"
#include "runtime-common/core/std/containers.h"
#include "runtime-common/stdlib/serialization/json-functions.h"
#include "runtime-common/stdlib/serialization/serialize-functions.h"
#include "runtime-light/coroutine/task.h"
#include "runtime-light/k2-platform/k2-api.h"
#include "runtime-light/stdlib/component/component-api.h"
#include "runtime-light/stdlib/confdata/confdata-constants.h"
#include "runtime-light/stdlib/confdata/confdata-state.h"
#include "runtime-light/stdlib/diagnostics/logs.h"
#include "runtime-light/stdlib/fork/fork-functions.h"
#include "runtime-light/streams/read-ext.h"
#include "runtime-light/streams/stream.h"
#include "runtime-light/tl/tl-core.h"
#include "runtime-light/tl/tl-functions.h"
#include "runtime-light/tl/tl-types.h"
namespace {
mixed extract_confdata_value(const tl::confdataValue& confdata_value) noexcept {
if (confdata_value.is_php_serialized.value && confdata_value.is_json_serialized.value) [[unlikely]] { // check that we don't have both flags set
kphp::log::warning("confdata value has both php_serialized and json_serialized flags set");
return {};
}
if (confdata_value.is_php_serialized.value) {
return unserialize_raw(confdata_value.value.value.data(), static_cast<string::size_type>(confdata_value.value.value.size()));
} else if (confdata_value.is_json_serialized.value) {
return json_decode(confdata_value.value.value).value_or(mixed{});
} else {
return string{confdata_value.value.value.data(), static_cast<string::size_type>(confdata_value.value.value.size())};
}
}
} // namespace
kphp::coro::task<mixed> f$confdata_get_value(string key) noexcept {
if (key.empty()) [[unlikely]] {
kphp::log::warning("empty key is not supported");
co_return mixed{};
}
auto& confdata_instance_st{ConfdataInstanceState::get()};
auto& confdata_key_cache{confdata_instance_st.key_cache()};
if (auto it{confdata_key_cache.find(key)}; it != confdata_key_cache.end()) {
co_return it->second;
}
k2::SystemTime start_time{};
k2::system_time(std::addressof(start_time));
const auto finalizer{vk::finally([&start_time, &confdata_instance_st] noexcept {
k2::SystemTime end_time{};
k2::system_time(std::addressof(end_time));
confdata_instance_st.time_ns += (end_time.since_epoch_ns - start_time.since_epoch_ns);
})};
tl::ConfdataGet confdata_get{.key = {.value = {key.c_str(), key.size()}}};
tl::storer tls{confdata_get.footprint()};
confdata_get.store(tls);
auto expected_stream{kphp::component::stream::open(kphp::confdata::COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return mixed{};
}
auto stream{*std::move(expected_stream)};
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response{};
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response)))) [[unlikely]] {
co_return mixed{};
}
tl::fetcher tlf{response};
tl::Maybe<tl::confdataValue> maybe_confdata_value{};
kphp::log::assertion(maybe_confdata_value.fetch(tlf));
if (!maybe_confdata_value.opt_value) { // no such key
co_return mixed{};
}
auto value{extract_confdata_value(*maybe_confdata_value.opt_value)}; // the key exists
confdata_key_cache.emplace(std::move(key), value);
co_return std::move(value);
}
kphp::coro::task<array<mixed>> f$confdata_get_values_by_any_wildcard(string wildcard) noexcept {
static constexpr size_t CONFDATA_GET_WILDCARD_INIT_BUFFER_CAPACITY = 1 << 20;
if (wildcard.empty()) [[unlikely]] {
kphp::log::warning("empty wildcard is not supported");
co_return array<mixed>{};
}
auto& confdata_instance_st{ConfdataInstanceState::get()};
auto& confdata_wildcard_cache{confdata_instance_st.wildcard_cache()};
if (auto it{confdata_wildcard_cache.find(wildcard)}; it != confdata_wildcard_cache.end()) {
co_return it->second;
}
k2::SystemTime start_time{};
k2::system_time(std::addressof(start_time));
const auto finalizer{vk::finally([&start_time, &confdata_instance_st] noexcept {
k2::SystemTime end_time{};
k2::system_time(std::addressof(end_time));
confdata_instance_st.time_ns += (end_time.since_epoch_ns - start_time.since_epoch_ns);
})};
const std::string_view wildcard_view{wildcard.c_str(), wildcard.size()};
const tl::ConfdataGetWildcard confdata_get_wildcard{.wildcard = {.value = wildcard_view}};
tl::storer tls{confdata_get_wildcard.footprint()};
confdata_get_wildcard.store(tls);
auto expected_stream{kphp::component::stream::open(kphp::confdata::COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return array<mixed>{};
}
auto stream{*std::move(expected_stream)};
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response{};
response.reserve(CONFDATA_GET_WILDCARD_INIT_BUFFER_CAPACITY);
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response)))) [[unlikely]] {
co_return array<mixed>{};
}
tl::fetcher tlf{response};
tl::Dictionary<tl::confdataValue> dict_confdata_value{};
kphp::log::assertion(dict_confdata_value.fetch(tlf));
array<mixed> result{array_size{static_cast<int64_t>(dict_confdata_value.size()), false}};
std::ranges::for_each(dict_confdata_value, [&result, wildcard_size = wildcard_view.size()](const auto& dict_field) noexcept {
kphp::log::assertion(dict_field.key.value.size() >= wildcard_size);
const std::string_view key_without_wildcard_prefix{dict_field.key.value.substr(wildcard_size)};
result.set_value(string{key_without_wildcard_prefix.data(), static_cast<string::size_type>(key_without_wildcard_prefix.size())},
extract_confdata_value(dict_field.value));
});
confdata_wildcard_cache.emplace(std::move(wildcard), result);
co_return std::move(result);
}