Skip to content

Commit

Permalink
K2: add confdata related builtins (#1110)
Browse files Browse the repository at this point in the history
  • Loading branch information
apolyakov authored Oct 9, 2024
1 parent 3385397 commit e4e470f
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 19 deletions.
12 changes: 12 additions & 0 deletions builtin-functions/kphp-light/confdata.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?

function is_confdata_loaded(): bool;

/** @kphp-extern-func-info interruptible */
function confdata_get_value($key ::: string): mixed;

/** @kphp-extern-func-info interruptible */
function confdata_get_values_by_any_wildcard($wildcard ::: string): mixed[];

/** @kphp-extern-func-info interruptible */
function confdata_get_values_by_predefined_wildcard($wildcard ::: string): mixed[];
1 change: 1 addition & 0 deletions builtin-functions/kphp-light/functions.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

require_once __DIR__ . '/array.txt';
require_once __DIR__ . '/confdata.txt';
require_once __DIR__ . '/crypto.txt';
require_once __DIR__ . '/hash.txt';
require_once __DIR__ . '/job-workers.txt';
Expand Down
7 changes: 0 additions & 7 deletions builtin-functions/kphp-light/unsupported/server.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ function debug_backtrace() ::: string[][];

function estimate_memory_usage($value ::: any) ::: int;

/** @kphp-extern-func-info generate-stub */
function is_confdata_loaded() ::: bool;
/** @kphp-extern-func-info generate-stub */
function confdata_get_value($key ::: string) ::: mixed;
/** @kphp-extern-func-info generate-stub */
function confdata_get_values_by_predefined_wildcard($wildcard ::: string) ::: mixed[];

/** @kphp-extern-func-info generate-stub */
function header ($str ::: string, $replace ::: bool = true, $http_response_code ::: int = 0) ::: void;
/** @kphp-extern-func-info generate-stub */
Expand Down
9 changes: 5 additions & 4 deletions runtime-light/component/component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <chrono>
#include <cstdint>
#include <memory>
#include <string_view>
#include <utility>

#include "runtime-core/utils/kphp-assert-core.h"
Expand Down Expand Up @@ -149,15 +150,15 @@ uint64_t ComponentState::take_incoming_stream() noexcept {
return stream_d;
}

uint64_t ComponentState::open_stream(const string &component_name) noexcept {
uint64_t ComponentState::open_stream(std::string_view component_name_view) noexcept {
uint64_t stream_d{};
if (const auto open_stream_res{get_platform_context()->open(component_name.size(), component_name.c_str(), std::addressof(stream_d))};
if (const auto open_stream_res{get_platform_context()->open(component_name_view.size(), component_name_view.data(), std::addressof(stream_d))};
open_stream_res != OpenStreamResult::OpenStreamOk) {
php_warning("can't open stream to %s", component_name.c_str());
php_warning("can't open stream to %s", component_name_view.data());
return INVALID_PLATFORM_DESCRIPTOR;
}
opened_streams_.insert(stream_d);
php_debug("opened a stream %" PRIu64 " to %s", stream_d, component_name.c_str());
php_debug("opened a stream %" PRIu64 " to %s", stream_d, component_name_view.data());
return stream_d;
}

Expand Down
8 changes: 7 additions & 1 deletion runtime-light/component/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <csetjmp>
#include <cstddef>
#include <cstdint>
#include <string_view>

#include "runtime-core/memory-resource/resource_allocator.h"
#include "runtime-core/memory-resource/unsynchronized_pool_resource.h"
Expand Down Expand Up @@ -85,7 +86,12 @@ struct ComponentState {
return standard_stream_;
}
uint64_t take_incoming_stream() noexcept;
uint64_t open_stream(const string &) noexcept;

uint64_t open_stream(std::string_view) noexcept;
uint64_t open_stream(const string &component_name) noexcept {
return open_stream(std::string_view{component_name.c_str(), static_cast<size_t>(component_name.size())});
}

uint64_t set_timer(std::chrono::nanoseconds) noexcept;
void release_stream(uint64_t) noexcept;
void release_all_streams() noexcept;
Expand Down
97 changes: 97 additions & 0 deletions runtime-light/stdlib/confdata/confdata-functions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// 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 <string>
#include <string_view>
#include <utility>

#include "runtime-core/runtime-core.h"
#include "runtime-core/utils/kphp-assert-core.h"
#include "runtime-light/component/component.h"
#include "runtime-light/coroutine/task.h"
#include "runtime-light/stdlib/component/component-api.h"
#include "runtime-light/tl/tl-core.h"
#include "runtime-light/tl/tl-functions.h"
#include "runtime-light/tl/tl-types.h"
#include "runtime-light/utils/context.h"
#include "runtime-light/utils/json-functions.h"

namespace {

constexpr auto *CONFDATA_COMPONENT_NAME = "confdata"; // TODO: it may actually have an alias specified in linking config
constexpr auto CONFDATA_COMPONENT_NAME_LENGTH = std::char_traits<char>::length(CONFDATA_COMPONENT_NAME);

mixed extract_confdata_value(tl::confdataValue &&confdata_value) noexcept {
if (confdata_value.is_php_serialized && confdata_value.is_json_serialized) { // check that we don't have both flags set
php_warning("confdata value has both php_serialized and json_serialized flags set");
return {};
}
if (confdata_value.is_php_serialized) {
php_critical_error("unimplemented"); // TODO
} else if (confdata_value.is_json_serialized) {
return f$json_decode(confdata_value.value);
} else {
return std::move(confdata_value.value);
}
}

} // namespace

// TODO: the performance of this implementation can be enhanced. rework it when the platform has specific API for that
bool f$is_confdata_loaded() noexcept {
auto &component_ctx{*get_component_context()};
if (const auto stream_d{component_ctx.open_stream(std::string_view{CONFDATA_COMPONENT_NAME})}; stream_d != INVALID_PLATFORM_DESCRIPTOR) {
component_ctx.release_stream(stream_d);
return true;
}
return false;
}

task_t<mixed> f$confdata_get_value(string key) noexcept {
tl::TLBuffer tlb{};
tl::ConfdataGet{.key = std::move(key)}.store(tlb);

auto query{co_await f$component_client_send_request({CONFDATA_COMPONENT_NAME, static_cast<string::size_type>(CONFDATA_COMPONENT_NAME_LENGTH)},
{tlb.data(), static_cast<string::size_type>(tlb.size())})};
const auto response{co_await f$component_client_fetch_response(std::move(query))};

tlb.clean();
tlb.store_bytes(response.c_str(), static_cast<size_t>(response.size()));
tl::Maybe<tl::confdataValue> maybe_confdata_value{};
if (!maybe_confdata_value.fetch(tlb)) {
php_warning("couldn't fetch response");
co_return mixed{};
}

if (!maybe_confdata_value.opt_value.has_value()) { // no such key
co_return mixed{};
}
co_return extract_confdata_value(*std::move(maybe_confdata_value.opt_value)); // the key exists
}

task_t<array<mixed>> f$confdata_get_values_by_any_wildcard(string wildcard) noexcept {
tl::TLBuffer tlb{};
tl::ConfdataGetWildcard{.wildcard = std::move(wildcard)}.store(tlb);

auto query{co_await f$component_client_send_request({CONFDATA_COMPONENT_NAME, static_cast<string::size_type>(CONFDATA_COMPONENT_NAME_LENGTH)},
{tlb.data(), static_cast<string::size_type>(tlb.size())})};
const auto response{co_await f$component_client_fetch_response(std::move(query))};

tlb.clean();
tlb.store_bytes(response.c_str(), static_cast<size_t>(response.size()));
tl::Dictionary<tl::confdataValue> dict_confdata_value{};
if (!dict_confdata_value.fetch(tlb)) {
php_warning("couldn't fetch response");
co_return array<mixed>{};
}

array<mixed> result{array_size{static_cast<int64_t>(dict_confdata_value.size()), false}};
std::for_each(dict_confdata_value.begin(), dict_confdata_value.end(),
[&result](auto &&dict_field) { result.set_value(std::move(dict_field.key), extract_confdata_value(std::move(dict_field.value))); });
co_return std::move(result);
}
20 changes: 20 additions & 0 deletions runtime-light/stdlib/confdata/confdata-functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Compiler for PHP (aka KPHP)
// Copyright (c) 2024 LLC «V Kontakte»
// Distributed under the GPL v3 License, see LICENSE.notice.txt

#pragma once

#include "runtime-core/runtime-core.h"
#include "runtime-core/utils/kphp-assert-core.h"
#include "runtime-light/coroutine/task.h"

bool f$is_confdata_loaded() noexcept;

task_t<mixed> f$confdata_get_value(string key) noexcept;

task_t<array<mixed>> f$confdata_get_values_by_any_wildcard(string wildcard) noexcept;

inline task_t<array<mixed>> f$confdata_get_values_by_predefined_wildcard(string wildcard) noexcept {
php_warning("K2 confdata does not support predefined wildcard optimization");
co_return(co_await f$confdata_get_values_by_any_wildcard(std::move(wildcard)));
}
1 change: 1 addition & 0 deletions runtime-light/stdlib/stdlib.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ prepend(
RUNTIME_STDLIB_SRC
stdlib/
component/component-api.cpp
confdata/confdata-functions.cpp
crypto/crypto-functions.cpp
curl/curl-context.cpp
exit/exit-functions.cpp
Expand Down
6 changes: 1 addition & 5 deletions runtime-light/tl/tl-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ namespace {
enum CertInfoItem : uint32_t { LONG_MAGIC = 0x533f'f89f, STR_MAGIC = 0xc427'feef, DICT_MAGIC = 0x1ea8'a774 };

constexpr uint32_t K2_JOB_WORKER_RESPONSE_MAGIC = 0x3afb'3a08;
constexpr uint32_t CONFDATA_VALUE_MAGIC = 0x3eaa'910b;

} // namespace

Expand Down Expand Up @@ -132,10 +131,7 @@ bool GetPemCertInfoResponse::fetch(TLBuffer &tlb) noexcept {
return true;
}

bool ConfdataValue::fetch(TLBuffer &tlb) noexcept {
if (tlb.fetch_trivial<uint32_t>().value_or(TL_ZERO) != CONFDATA_VALUE_MAGIC) {
return false;
}
bool confdataValue::fetch(TLBuffer &tlb) noexcept {
const auto value_view{tlb.fetch_string()};
Bool is_php_serialized_{};
Bool is_json_serialized_{};
Expand Down
30 changes: 28 additions & 2 deletions runtime-light/tl/tl-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ struct dictionaryField final {
bool fetch(TLBuffer &tlb) noexcept requires tl_deserializable<T> {
const auto key_view{tlb.fetch_string()};
key = {key_view.data(), static_cast<string::size_type>(key_view.size())};
return !value.fetch(tlb);
return value.fetch(tlb);
}

void store(TLBuffer &tlb) const noexcept requires tl_serializable<T> {
Expand Down Expand Up @@ -221,6 +221,32 @@ template<typename T>
struct Dictionary final {
dictionary<T> data{};

using iterator = dictionary<T>::iterator;
using const_iterator = dictionary<T>::const_iterator;

iterator begin() noexcept {
return data.begin();
}
iterator end() noexcept {
return data.end();
}
const_iterator begin() const noexcept {
return data.begin();
}
const_iterator end() const noexcept {
return data.end();
}
const_iterator cbegin() const noexcept {
return data.cbegin();
}
const_iterator cend() const noexcept {
return data.cend();
}

size_t size() const noexcept {
return data.size();
}

bool fetch(TLBuffer &tlb) noexcept requires tl_deserializable<T> {
if (tlb.fetch_trivial<uint32_t>().value_or(TL_ZERO) != TL_DICTIONARY) {
return false;
Expand Down Expand Up @@ -270,7 +296,7 @@ enum DigestAlgorithm : uint32_t {

// ===== CONFDATA =====

struct ConfdataValue final {
struct confdataValue final {
string value;
bool is_php_serialized{};
bool is_json_serialized{};
Expand Down
30 changes: 30 additions & 0 deletions tests/k2-components/test_confdata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?

function test_confdata_get_value(): bool {
$existing = confdata_get_value("now");
$missing = confdata_get_value("missing_key");
return !is_null($existing) && is_null($missing);
}

function test_confdata_get_values_by_any_wildcard(): bool {
$existing1 = confdata_get_values_by_any_wildcard("n");
$existing2 = confdata_get_values_by_any_wildcard("no");
$existing3 = confdata_get_values_by_any_wildcard("now");
$missing = confdata_get_values_by_any_wildcard("missing_wildcard");
return !empty($existing1) && !empty($existing2) && !empty($existing3) && empty($missing);
}

function test_confdata_get_values_by_predefined_wildcard(): bool {
$existing1 = confdata_get_values_by_predefined_wildcard("n");
$existing2 = confdata_get_values_by_predefined_wildcard("no");
$existing3 = confdata_get_values_by_predefined_wildcard("now");
$missing = confdata_get_values_by_predefined_wildcard("missing_wildcard");
return !empty($existing1) && !empty($existing2) && !empty($existing3) && empty($missing);
}

$query = component_server_accept_query();
if (test_confdata_get_value() && test_confdata_get_values_by_any_wildcard() && test_confdata_get_values_by_predefined_wildcard()) {
component_server_send_response($query, "OK");
} else {
component_server_send_response($query, "FAIL");
}

0 comments on commit e4e470f

Please sign in to comment.