Modernize the transaction API

PiperOrigin-RevId: 295712938
Change-Id: Iaf4c9668bb0b48555679fef822fe424277540d1f
This commit is contained in:
Christian Blichmann 2020-02-18 05:27:08 -08:00 committed by Copybara-Service
parent 5b1119aa6d
commit d578b18c22
4 changed files with 49 additions and 50 deletions

View File

@ -58,7 +58,7 @@ class SumTransaction : public sapi::Transaction {
};
sapi::Status SumTransaction::Main() {
SumApi f(GetSandbox());
SumApi f(sandbox());
SAPI_ASSIGN_OR_RETURN(int v, f.sum(1000, 337));
LOG(INFO) << "1000 + 337 = " << v;
TRANSACTION_FAIL_IF_NOT(v == 1337, "1000 + 337 != 1337");
@ -89,10 +89,10 @@ sapi::Status SumTransaction::Main() {
// Gets symbol address and prints its value.
int* ssaddr;
SAPI_RETURN_IF_ERROR(
GetSandbox()->Symbol("sumsymbol", reinterpret_cast<void**>(&ssaddr)));
sandbox()->Symbol("sumsymbol", reinterpret_cast<void**>(&ssaddr)));
sapi::v::Int sumsymbol;
sumsymbol.SetRemote(ssaddr);
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferFromSandboxee(&sumsymbol));
SAPI_RETURN_IF_ERROR(sandbox()->TransferFromSandboxee(&sumsymbol));
LOG(INFO) << "sumsymbol value (exp: 5): " << sumsymbol.GetValue()
<< ", address: " << ssaddr;
TRANSACTION_FAIL_IF_NOT(sumsymbol.GetValue() == 5,
@ -120,7 +120,7 @@ sapi::Status SumTransaction::Main() {
LOG(INFO) << "Print: '" << hwstr << "' via puts()";
sapi::v::Array<const char> hwarr(hwstr, sizeof(hwstr));
sapi::v::Int ret;
SAPI_RETURN_IF_ERROR(GetSandbox()->Call("puts", &ret, hwarr.PtrBefore()));
SAPI_RETURN_IF_ERROR(sandbox()->Call("puts", &ret, hwarr.PtrBefore()));
TRANSACTION_FAIL_IF_NOT(ret.GetValue() == 15, "puts('Hello World!!!') != 15");
sapi::v::Int vp;
@ -144,13 +144,13 @@ sapi::Status SumTransaction::Main() {
// Fd transfer test.
int fdesc = open("/proc/self/exe", O_RDONLY);
sapi::v::Fd fd(fdesc);
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferToSandboxee(&fd));
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&fd));
LOG(INFO) << "remote_fd = " << fd.GetRemoteFd();
TRANSACTION_FAIL_IF_NOT(fd.GetRemoteFd() == 3, "remote_fd != 3");
fdesc = open("/proc/self/comm", O_RDONLY);
sapi::v::Fd fd2(fdesc);
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferToSandboxee(&fd2));
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&fd2));
LOG(INFO) << "remote_fd2 = " << fd2.GetRemoteFd();
TRANSACTION_FAIL_IF_NOT(fd2.GetRemoteFd() == 4, "remote_fd2 != 4");
@ -158,19 +158,19 @@ sapi::Status SumTransaction::Main() {
char buffer[1024] = {0};
sapi::v::Array<char> buf(buffer, sizeof(buffer));
sapi::v::UInt size(128);
SAPI_RETURN_IF_ERROR(GetSandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
SAPI_RETURN_IF_ERROR(sandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
LOG(INFO) << "Read from /proc/self/comm = [" << buffer << "]";
// Close test.
SAPI_RETURN_IF_ERROR(fd2.CloseRemoteFd(GetSandbox()->GetRpcChannel()));
SAPI_RETURN_IF_ERROR(fd2.CloseRemoteFd(sandbox()->GetRpcChannel()));
memset(buffer, 0, sizeof(buffer));
SAPI_RETURN_IF_ERROR(GetSandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
SAPI_RETURN_IF_ERROR(sandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
LOG(INFO) << "Read from closed /proc/self/comm = [" << buffer << "]";
// Pass fd as function arg example.
fdesc = open("/proc/self/statm", O_RDONLY);
sapi::v::Fd fd3(fdesc);
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferToSandboxee(&fd3));
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&fd3));
SAPI_ASSIGN_OR_RETURN(int r2, f.read_int(fd3.GetRemoteFd()));
LOG(INFO) << "statm value (should not be 0) = " << r2;

View File

@ -72,10 +72,10 @@ void BenchmarkSandboxRestartOverhead(benchmark::State& state) {
BENCHMARK(BenchmarkSandboxRestartOverhead);
void BenchmarkSandboxRestartForkserverOverhead(benchmark::State& state) {
sapi::BasicTransaction st{absl::make_unique<StringopSandbox>()};
sapi::BasicTransaction st(absl::make_unique<StringopSandbox>());
for (auto _ : state) {
EXPECT_THAT(st.Run(InvokeNop), IsOk());
EXPECT_THAT(st.GetSandbox()->Restart(true), IsOk());
EXPECT_THAT(st.sandbox()->Restart(true), IsOk());
}
}
BENCHMARK(BenchmarkSandboxRestartForkserverOverhead);
@ -84,7 +84,7 @@ void BenchmarkSandboxRestartForkserverOverheadForced(benchmark::State& state) {
sapi::BasicTransaction st{absl::make_unique<StringopSandbox>()};
for (auto _ : state) {
EXPECT_THAT(st.Run(InvokeNop), IsOk());
EXPECT_THAT(st.GetSandbox()->Restart(false), IsOk());
EXPECT_THAT(st.sandbox()->Restart(false), IsOk());
}
}
BENCHMARK(BenchmarkSandboxRestartForkserverOverheadForced);

View File

@ -23,23 +23,23 @@ constexpr absl::Duration TransactionBase::kDefaultTimeLimit;
sapi::Status TransactionBase::RunTransactionFunctionInSandbox(
const std::function<sapi::Status()>& f) {
// Run Main(), invoking Init() if this hasn't been yet done.
SAPI_RETURN_IF_ERROR(GetSandbox()->Init());
SAPI_RETURN_IF_ERROR(sandbox_->Init());
// Set the wall-time limit for this transaction run, and clean it up
// afterwards, no matter what the result.
SAPI_RETURN_IF_ERROR(GetSandbox()->SetWallTimeLimit(GetTimeLimit()));
SAPI_RETURN_IF_ERROR(sandbox_->SetWallTimeLimit(GetTimeLimit()));
struct TimeCleanup {
~TimeCleanup() {
if (capture->GetSandbox()->IsActive()) {
capture->GetSandbox()->SetWallTimeLimit(0).IgnoreError();
if (capture->sandbox_->IsActive()) {
capture->sandbox_->SetWallTimeLimit(0).IgnoreError();
}
}
TransactionBase* capture;
} sandbox_cleanup{this};
} sandbox_cleanup = {this};
if (!GetInited()) {
if (!initialized_) {
SAPI_RETURN_IF_ERROR(Init());
SetInited(true);
initialized_ = true;
}
return f();
@ -50,24 +50,24 @@ sapi::Status TransactionBase::RunTransactionLoop(
// Try to run Main() for a few times, return error if none of the tries
// succeeded.
sapi::Status status;
for (int i = 0; i <= GetRetryCnt(); i++) {
for (int i = 0; i <= retry_count_; ++i) {
status = RunTransactionFunctionInSandbox(f);
if (status.ok()) {
return status;
}
GetSandbox()->Terminate();
SetInited(false);
sandbox_->Terminate();
initialized_ = false;
}
LOG(ERROR) << "Tried " << (GetRetryCnt() + 1) << " times to run the "
LOG(ERROR) << "Tried " << (retry_count_ + 1) << " times to run the "
<< "transaction, but it failed. SAPI error: '" << status
<< "'. Latest sandbox error: '"
<< GetSandbox()->AwaitResult().ToString() << "'";
<< sandbox_->AwaitResult().ToString() << "'";
return status;
}
TransactionBase::~TransactionBase() {
if (GetInited()) {
if (initialized_) {
Finish().IgnoreError();
}
}

View File

@ -51,13 +51,14 @@ class TransactionBase {
public:
TransactionBase(const TransactionBase&) = delete;
TransactionBase& operator=(const TransactionBase&) = delete;
virtual ~TransactionBase();
// Getter/Setter for retry_cnt_.
int GetRetryCnt() const { return retry_cnt_; }
void SetRetryCnt(int retry_count) {
CHECK_GE(retry_count, 0);
retry_cnt_ = retry_count;
// Getter/Setter for retry_count_.
int retry_count() const { return retry_count_; }
void set_retry_count(int value) {
CHECK_GE(value, 0);
retry_count_ = value;
}
// Getter/Setter for time_limit_.
@ -67,30 +68,28 @@ class TransactionBase {
time_limit_ = absl::ToTimeT(absl::UnixEpoch() + time_limit);
}
// Getter/Setter for inited_.
bool GetInited() const { return inited_; }
void SetInited(bool inited) { inited_ = inited; }
bool IsInitialized() const { return initialized_; }
// Getter for the sandbox_.
Sandbox* GetSandbox() { return sandbox_.get(); }
Sandbox* sandbox() const { return sandbox_.get(); }
// Restarts the sandbox.
// WARNING: This will invalidate any references to the remote process, make
// sure you don't keep any var's or FD's to the remote process when calling
// this.
// sure you don't keep any vars or FDs to the remote process when
// calling this.
sapi::Status Restart() {
if (inited_) {
if (initialized_) {
Finish().IgnoreError();
inited_ = false;
initialized_ = false;
}
return sandbox_->Restart(true);
}
protected:
explicit TransactionBase(std::unique_ptr<Sandbox> sandbox)
: retry_cnt_(kDefaultRetryCnt),
: retry_count_(kDefaultRetryCount),
time_limit_(absl::ToTimeT(absl::UnixEpoch() + kDefaultTimeLimit)),
inited_(false),
initialized_(false),
sandbox_(std::move(sandbox)) {}
// Runs the main (retrying) transaction loop.
@ -98,7 +97,7 @@ class TransactionBase {
private:
// Number of default transaction execution re-tries, in case of failures.
static constexpr int kDefaultRetryCnt = 1;
static constexpr int kDefaultRetryCount = 1;
// Wall-time limit for a single transaction execution (60 s.).
static constexpr absl::Duration kDefaultTimeLimit = absl::Seconds(60);
@ -108,7 +107,7 @@ class TransactionBase {
sapi::Status RunTransactionFunctionInSandbox(
const std::function<sapi::Status()>& f);
// Initialization routine of the sandboxed process that ill be called only
// Initialization routine of the sandboxed process that will be called only
// once upon sandboxee startup.
virtual sapi::Status Init() { return sapi::OkStatus(); }
@ -117,14 +116,14 @@ class TransactionBase {
virtual sapi::Status Finish() { return sapi::OkStatus(); }
// Number of tries this transaction will be re-executed until it succeeds.
int retry_cnt_;
int retry_count_;
// Time (wall-time) limit for a single Run() call (in seconds). 0 means: no
// wall-time limit.
time_t time_limit_;
// Has Init() finished with success?
bool inited_;
bool initialized_;
// The main sapi::Sandbox object.
std::unique_ptr<Sandbox> sandbox_;
@ -172,13 +171,13 @@ class BasicTransaction final : public TransactionBase {
init_function_(static_cast<InitFunction>(init_function)),
finish_function_(static_cast<FinishFunction>(fini_function)) {}
// Run any function as body of the transaction that matches our expectations (
// that is: Returning a sapi::Status and accepting a Sandbox object as first
// Run any function as body of the transaction that matches our expectations
// (that is: Returning a Status and accepting a Sandbox object as first
// parameter).
template <typename T, typename... Args>
sapi::Status Run(T func, Args&&... args) {
return RunTransactionLoop(
[&] { return func(GetSandbox(), std::forward<Args>(args)...); });
[&] { return func(sandbox(), std::forward<Args>(args)...); });
}
private:
@ -186,11 +185,11 @@ class BasicTransaction final : public TransactionBase {
FinishFunction finish_function_;
sapi::Status Init() final {
return init_function_ ? init_function_(GetSandbox()) : sapi::OkStatus();
return init_function_ ? init_function_(sandbox()) : sapi::OkStatus();
}
sapi::Status Finish() final {
return finish_function_ ? finish_function_(GetSandbox()) : sapi::OkStatus();
return finish_function_ ? finish_function_(sandbox()) : sapi::OkStatus();
}
};