Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8d8961a
SY-3961: Register ranges module in Arc root
sy-nico Jun 18, 2026
9b5e067
SY-3961: Remove `ranges.start` and the `create` time/label params
sy-nico Jun 22, 2026
2ff2eaa
SY-3961: `color` validation
sy-nico Jun 22, 2026
1e76cc3
SY-3961: Make ranges.end atomic via ranger.SetEnd to fix read-modify-…
sy-nico Jun 22, 2026
0283c2f
SY-3961: Accept rgb()/rgba() colors in ranges.create
sy-nico Jun 22, 2026
8bb88b5
SY-3961: Allow computed expressions in Arc flow brace inputs
sy-nico Jun 22, 2026
4baea40
SY-3961: Add go tests
sy-nico Jun 22, 2026
8928385
SY-3961: Mirror Arc ranges module and expression inputs on the C++ dr…
sy-nico Jun 22, 2026
35bc25b
SY-3961: fix test
sy-nico Jun 23, 2026
6bf5397
Merge remote-tracking branch 'origin/rc' into sy-3961-arc-ranges-v2
sy-nico Jun 23, 2026
d916b2b
SY-3961: Simplify ranges.end to key-only and revert computed brace in…
sy-nico Jun 23, 2026
883d9a9
SY-3961: Integration test
sy-nico Jun 23, 2026
938c481
[formatting]
sy-nico Jun 23, 2026
d40239d
SY-3961: Documentation
sy-nico Jun 23, 2026
c960b23
Merge remote-tracking branch 'origin/rc' into sy-3961-arc-ranges-v2
sy-nico Jun 23, 2026
d296782
SY-3961: Fix CI test failures for the Arc ranges module
sy-nico Jun 23, 2026
8fb8e5e
SY-3961: nit fixes
sy-nico Jun 24, 2026
823f2d8
SY-3961: Cover the Arc color CSS parsing branches
sy-nico Jun 24, 2026
112b308
SY-3961: Fix doc examples
sy-nico Jun 24, 2026
c03a2eb
SY-3961: Add a single-round-trip ranges set_end API
sy-nico Jun 24, 2026
8f66f08
SY-3961: Harden Arc color parsing per review
sy-nico Jun 24, 2026
9b9f84c
SY-3961: Return node.Factory from the Arc ranges and status modules
sy-nico Jun 24, 2026
c660fa2
SY-3961: make timestamp max a constant
sy-nico Jun 24, 2026
1d4af64
SY-3961: Test corrections and additions
sy-nico Jun 24, 2026
9f062a8
Merge remote-tracking branch 'origin/rc' into sy-3961-arc-ranges-v2
sy-nico Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions client/cpp/ranger/ranger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,12 @@ Client::create(const std::string &name, x::telem::TimeRange time_range) const {
return {rng, err};
}

x::errors::Error
Client::set_end(const x::uuid::UUID &key, const x::telem::TimeStamp end) const {
auto req = grpc::ranger::SetEndRequest();
req.set_key(key.to_string());
req.set_end(end.nanoseconds());
return set_end_client->send("/range/set-end", req).second;
}

}
13 changes: 13 additions & 0 deletions client/cpp/ranger/ranger.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,22 @@ using RetrieveClient = freighter::
using CreateClient = freighter::
UnaryClient<grpc::ranger::CreateRequest, grpc::ranger::CreateResponse>;

/// @brief type alias for the transport used to set the end bound of a range.
using SetEndClient = freighter::
UnaryClient<grpc::ranger::SetEndRequest, google::protobuf::Empty>;

/// @brief a client for performing operations on the ranges in a Synnax cluster.
class Client {
public:
Client(
std::unique_ptr<RetrieveClient> retrieve_client,
std::unique_ptr<CreateClient> create_client,
std::unique_ptr<SetEndClient> set_end_client,
const ranger::kv::Client &kv_client
):
retrieve_client(std::move(retrieve_client)),
create_client(std::move(create_client)),
set_end_client(std::move(set_end_client)),
kv(kv_client) {}

/// @brief retrieves the range with the given key.
Expand Down Expand Up @@ -70,11 +76,18 @@ class Client {
[[nodiscard]] std::pair<Range, x::errors::Error>
create(const std::string &name, x::telem::TimeRange time_range) const;

/// @brief sets the end bound of the range with the given key in a single request,
/// preserving all other fields.
[[nodiscard]] x::errors::Error
set_end(const Key &key, x::telem::TimeStamp end) const;

private:
/// @brief range retrieval transport.
std::unique_ptr<RetrieveClient> retrieve_client;
/// @brief create retrieval transport.
std::unique_ptr<CreateClient> create_client;
/// @brief set-end transport.
std::unique_ptr<SetEndClient> set_end_client;
/// @brief range kv get transport.
ranger::kv::Client kv;

Expand Down
23 changes: 23 additions & 0 deletions client/cpp/ranger/ranger_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,29 @@ TEST(RangerTests, testRetrieveByKey) {
ASSERT_EQ(got.time_range.end, x::telem::TimeStamp(100));
}

/// @brief it should set the end bound of a range while preserving its other fields.
TEST(RangerTests, testSetEnd) {
const auto client = new_test_client();
const auto range = ASSERT_NIL_P(client.ranges.create(
"test",
x::telem::TimeRange(x::telem::TimeStamp(30), x::telem::TimeStamp(100))
));
ASSERT_NIL(client.ranges.set_end(range.key, x::telem::TimeStamp(500)));
const auto got = ASSERT_NIL_P(client.ranges.retrieve_by_key(range.key));
ASSERT_EQ(got.name, "test");
ASSERT_EQ(got.time_range.start, x::telem::TimeStamp(30));
ASSERT_EQ(got.time_range.end, x::telem::TimeStamp(500));
}

/// @brief it should return an error when setting the end of a nonexistent range.
TEST(RangerTests, testSetEndNotFound) {
const auto client = new_test_client();
ASSERT_OCCURRED_AS(
client.ranges.set_end(x::uuid::create(), x::telem::TimeStamp(500)),
x::errors::NOT_FOUND
);
}

/// @brief it should retrieve a range by its name.
TEST(RangerTests, testRetrieveByName) {
const auto client = new_test_client();
Expand Down
1 change: 1 addition & 0 deletions client/cpp/synnax.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class Synnax {
ranges(
std::move(this->t.range_retrieve),
std::move(this->t.range_create),
std::move(this->t.range_set_end),
ranger::kv::Client(
this->t.range_kv_get,
this->t.range_kv_set,
Expand Down
5 changes: 5 additions & 0 deletions client/cpp/transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ Transport::Transport(
grpc::ranger::CreateRequest,
grpc::ranger::CreateResponse,
grpc::ranger::RangeCreateService>>(pool, base_target);
this->range_set_end = std::make_unique<freighter::grpc::UnaryClient<
grpc::ranger::SetEndRequest,
google::protobuf::Empty,
grpc::ranger::RangeSetEndService>>(pool, base_target);
this->range_kv_delete = std::make_shared<freighter::grpc::UnaryClient<
grpc::kv::DeleteRequest,
google::protobuf::Empty,
Expand Down Expand Up @@ -180,6 +184,7 @@ void Transport::use(const std::shared_ptr<freighter::Middleware> &mw) const {
chan_retrieve->use(mw);
range_retrieve->use(mw);
range_create->use(mw);
range_set_end->use(mw);
range_kv_delete->use(mw);
range_kv_get->use(mw);
range_kv_set->use(mw);
Expand Down
1 change: 1 addition & 0 deletions client/cpp/transport.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct Transport {
std::shared_ptr<channel::RetrieveClient> chan_retrieve;
std::unique_ptr<ranger::RetrieveClient> range_retrieve;
std::unique_ptr<ranger::CreateClient> range_create;
std::unique_ptr<ranger::SetEndClient> range_set_end;
std::shared_ptr<ranger::kv::DeleteClient> range_kv_delete;
std::shared_ptr<ranger::kv::GetClient> range_kv_get;
std::shared_ptr<ranger::kv::SetClient> range_kv_set;
Expand Down
3 changes: 3 additions & 0 deletions core/pkg/api/layer.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type Transport struct {
RangeRetrieve freighter.UnaryServer[ranger.RetrieveRequest, ranger.RetrieveResponse]
RangeDelete freighter.UnaryServer[ranger.DeleteRequest, types.Nil]
RangeRename freighter.UnaryServer[ranger.RenameRequest, types.Nil]
RangeSetEnd freighter.UnaryServer[ranger.SetEndRequest, types.Nil]
// KV
KVGet freighter.UnaryServer[kv.GetRequest, kv.GetResponse]
KVSet freighter.UnaryServer[kv.SetRequest, types.Nil]
Expand Down Expand Up @@ -281,6 +282,7 @@ func (l *Layer) BindTo(t Transport) {
t.RangeRetrieve,
t.RangeDelete,
t.RangeRename,
t.RangeSetEnd,

// KV
t.KVGet,
Expand Down Expand Up @@ -447,6 +449,7 @@ func (l *Layer) BindTo(t Transport) {
t.RangeCreate.BindHandler(fgorp.CreateWriteUnaryHandler(db, l.Range.Create))
t.RangeDelete.BindHandler(fgorp.CreateWriteUnaryHandler(db, l.Range.Delete))
t.RangeRename.BindHandler(fgorp.CreateWriteUnaryHandler(db, l.Range.Rename))
t.RangeSetEnd.BindHandler(fgorp.CreateWriteUnaryHandler(db, l.Range.SetEnd))

// KV
t.KVGet.BindHandler(l.KV.Get)
Expand Down
20 changes: 20 additions & 0 deletions core/pkg/api/ranger/ranger.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,26 @@ func (s *Service) Rename(
return types.Nil{}, s.internal.NewWriter(tx).Rename(ctx, req.Key, req.Name)
}

type SetEndRequest struct {
Key ranger.Key `json:"key" msgpack:"key"`
End telem.TimeStamp `json:"end" msgpack:"end"`
}

func (s *Service) SetEnd(
ctx context.Context,
tx gorp.Tx,
req SetEndRequest,
) (types.Nil, error) {
if err := s.access.NewEnforcer(tx).Enforce(ctx, access.Request{
Subject: auth.GetSubject(ctx),
Action: access.ActionUpdate,
Objects: []ontology.ID{ranger.OntologyID(req.Key)},
}); err != nil {
return types.Nil{}, err
}
return types.Nil{}, s.internal.NewWriter(tx).SetEnd(ctx, req.Key, req.End)
}

type DeleteRequest struct {
Keys []ranger.Key `json:"keys" msgpack:"keys"`
}
Expand Down
Loading
Loading