Skip to content

Commit

Permalink
nixd/nix-node-eval: init
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Mar 14, 2024
1 parent 330850a commit e73596a
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 0 deletions.
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if git.found()
endif

config_h.set_quoted('NIXD_VERSION', meson.project_version())
config_h.set_quoted('NIXD_LIBEXEC', get_option('prefix') / get_option('libexecdir'))

configure_file(
output: 'nixd-config.h',
Expand Down
1 change: 1 addition & 0 deletions nixd/meson.build
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
subdir('librpc')
subdir('libutil')
subdir('nix-node-eval')
subdir('tools')
3 changes: 3 additions & 0 deletions nixd/nix-node-eval/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# nix-node-eval

Collect per-node eval information, by using official evaluator.
31 changes: 31 additions & 0 deletions nixd/nix-node-eval/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
nixd_nix_node_eval_deps = [ libnixdrpc, nixt, libnixdutil ]

nixd_nix_node_eval_lib = library(
'nix-node-eval',
'src/EvalProvider.cpp',
install: true,
dependencies: nixd_nix_node_eval_deps
)

nixd_nix_node_eval_lib_dep = declare_dependency(
link_with: nixd_nix_node_eval_lib,
dependencies: nixd_nix_node_eval_deps,
)


nixd_nix_node_eval = executable('nix-node-eval',
'src/Main.cpp',
install: true,
install_dir: get_option('libexecdir'),
dependencies: nixd_nix_node_eval_lib_dep
)

test(
'unit/nixd/nix-node-eval',
executable(
'unit-nixd-nix-node-eval',
'test/EvalProvider.cpp',
dependencies: [ nixd_nix_node_eval_lib_dep, gtest_main],
include_directories: include_directories('src')
)
)
100 changes: 100 additions & 0 deletions nixd/nix-node-eval/src/EvalProvider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "EvalProvider.h"

#include "nixd/rpc/Protocol.h"

#include <nixt/Deserialize.h>
#include <nixt/HackCache.h>

#include <bc/Read.h>
#include <bc/Write.h>

#include <nix/canon-path.hh>
#include <nix/eval.hh>
#include <nix/fs-input-accessor.hh>
#include <nix/input-accessor.hh>
#include <nix/nixexpr.hh>
#include <nix/store-api.hh>

#include <boost/interprocess/creation_tags.hpp>
#include <boost/interprocess/detail/os_file_functions.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/shared_memory_object.hpp>

namespace nixd {

using bc::readBytecode;
using rpc::readBytecode;

namespace bipc = boost::interprocess;

using namespace rpc;

EvalProvider::EvalProvider(int InboundFD, int OutboundFD)
: rpc::Transport(InboundFD, OutboundFD),
State(std::unique_ptr<nix::EvalState>(
new nix::EvalState{{}, nix::openStore("dummy://")})) {}

void EvalProvider::handleInbound(const std::vector<char> &Buf) {
std::ostringstream OS;
rpc::RPCKind Kind;
std::string_view Data(Buf.data(), Buf.size());
readBytecode(Data, Kind);
switch (Kind) {
case rpc::RPCKind::RegisterBC: {
rpc::RegisterBCParams Params;
readBytecode(Data, Params);
onRegisterBC(Params);
break;
}
case rpc::RPCKind::UnregisterBC:
case rpc::RPCKind::Log:
case rpc::RPCKind::ExprValue: {
rpc::ExprValueParams Params;
readBytecode(Data, Params);
rpc::ExprValueResponse Response = onExprValue(Params);
sendPacket<ExprValueResponse>(Response);
break;
}
}
}

void EvalProvider::onRegisterBC(const rpc::RegisterBCParams &Params) {
// Path context
auto CachePath = State->rootPath(nix::CanonPath(Params.CachePath));

nixt::DeserializeContext Ctx = nixt::getDeserializeContext(
*State, Params.BasePath, nix::Pos::none_tag{});

// Extract the buffer from `Params`
bipc::shared_memory_object Shm(bipc::open_only, Params.Shm.c_str(),
bipc::read_only);

bipc::mapped_region Region(Shm, bipc::read_only);

std::string_view RegionView = {(char *)Region.get_address(),
(char *)Region.get_address() + Params.Size};

nix::Expr *AST = nixt::deserializeHookable(RegionView, Ctx, Pool, VMap, EMap);

nix::Value V;
State->eval(AST, V);

// Inject pre-parsed AST into EvalState cache
auto Cache = nixt::getFileParseCache(*State);
Cache[CachePath] = AST;
}

ExprValueResponse EvalProvider::onExprValue(const ExprValueParams &Params) {
if (VMap.contains(Params.ExprID)) {
nix::Value V = VMap[Params.ExprID];

return {
ExprValueResponse::OK,
static_cast<uintptr_t>(V.integer),
ExprValueResponse::Int,
};
}
return {ExprValueResponse::NotEvaluated, 99};
}

} // namespace nixd
30 changes: 30 additions & 0 deletions nixd/nix-node-eval/src/EvalProvider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "nixd/rpc/Protocol.h"
#include "nixd/rpc/Transport.h"

#include <nixt/HookExpr.h>
#include <nixt/PtrPool.h>

#include <nix/nixexpr.hh>

namespace nixd {

class EvalProvider : public rpc::Transport {

nixt::PtrPool<nix::Expr> Pool;
nixt::ValueMap VMap;
nixt::EnvMap EMap;
std::unique_ptr<nix::EvalState> State;

void handleInbound(const std::vector<char> &Buf) override;

public:
EvalProvider(int InboundFD, int OutboundFD);

void onRegisterBC(const rpc::RegisterBCParams &Params);

rpc::ExprValueResponse onExprValue(const rpc::ExprValueParams &Params);
};

} // namespace nixd
12 changes: 12 additions & 0 deletions nixd/nix-node-eval/src/Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

#include "EvalProvider.h"

#include <nixt/InitEval.h>

#include <unistd.h>

int main() {
nixt::initEval();
nixd::EvalProvider Provider(STDIN_FILENO, STDOUT_FILENO);
return Provider.run();
}
44 changes: 44 additions & 0 deletions nixd/nix-node-eval/test/EvalProvider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <gtest/gtest.h>

#include "EvalProvider.h"

#include "nixd/rpc/Protocol.h"
#include "nixd/rpc/Transport.h"

#include <nixt/InitEval.h>

#include <unistd.h>

namespace {

using namespace nixd::rpc;

#define READ 0
#define WRITE 1

struct TestEvalProvider : testing::Test {
int Pipes[2][2];

TestEvalProvider() { nixt::initEval(); }
};

TEST_F(TestEvalProvider, ExprValue) {
ASSERT_EQ(pipe(Pipes[READ]), 0);
ASSERT_EQ(pipe(Pipes[WRITE]), 0);

nixd::EvalProvider Provider(Pipes[READ][READ], Pipes[WRITE][WRITE]);

sendPacket<Message<ExprValueParams>>(Pipes[READ][WRITE],
{RPCKind::ExprValue, {}});

close(Pipes[READ][WRITE]);

[[maybe_unused]] int Result = Provider.run();

auto Packet = recvPacket<ExprValueResponse>(Pipes[WRITE][READ]);

ASSERT_EQ(Packet.ValueID, 0);
ASSERT_EQ(Packet.ValueKind, 0);
}

} // namespace

0 comments on commit e73596a

Please sign in to comment.