Skip to content

Commit e12e9f2

Browse files
author
eldritch horrors
committed
Merge pull request NixOS#9137 from obsidiansystems/serve-protocol
Introduce separate Serve protocol serialisers (cherry picked from commit d070d8b) Change-Id: Ibcc8639e8997bcd07f7a5318330a147bcadc411b
1 parent aeb803d commit e12e9f2

File tree

15 files changed

+344
-39
lines changed

15 files changed

+344
-39
lines changed

src/libstore/legacy-ssh-store.cc

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
#include "pool.hh"
44
#include "remote-store.hh"
55
#include "serve-protocol.hh"
6+
#include "serve-protocol-impl.hh"
67
#include "build-result.hh"
78
#include "store-api.hh"
89
#include "path-with-outputs.hh"
9-
#include "common-protocol.hh"
10-
#include "common-protocol-impl.hh"
1110
#include "ssh.hh"
1211
#include "derivations.hh"
1312
#include "callback.hh"
@@ -50,37 +49,31 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
5049
bool good = true;
5150

5251
/**
53-
* Coercion to `CommonProto::ReadConn`. This makes it easy to use the
54-
* factored out common protocol serialisers with a
52+
* Coercion to `ServeProto::ReadConn`. This makes it easy to use the
53+
* factored out serve protocol searlizers with a
5554
* `LegacySSHStore::Connection`.
5655
*
57-
* The common protocol connection types are unidirectional, unlike
56+
* The serve protocol connection types are unidirectional, unlike
5857
* this type.
59-
*
60-
* @todo Use server protocol serializers, not common protocol
61-
* serializers, once we have made that distiction.
6258
*/
63-
operator CommonProto::ReadConn ()
59+
operator ServeProto::ReadConn ()
6460
{
65-
return CommonProto::ReadConn {
61+
return ServeProto::ReadConn {
6662
.from = from,
6763
};
6864
}
6965

7066
/*
71-
* Coercion to `CommonProto::WriteConn`. This makes it easy to use the
72-
* factored out common protocol searlizers with a
67+
* Coercion to `ServeProto::WriteConn`. This makes it easy to use the
68+
* factored out serve protocol searlizers with a
7369
* `LegacySSHStore::Connection`.
7470
*
75-
* The common protocol connection types are unidirectional, unlike
71+
* The serve protocol connection types are unidirectional, unlike
7672
* this type.
77-
*
78-
* @todo Use server protocol serializers, not common protocol
79-
* serializers, once we have made that distiction.
8073
*/
81-
operator CommonProto::WriteConn ()
74+
operator ServeProto::WriteConn ()
8275
{
83-
return CommonProto::WriteConn {
76+
return ServeProto::WriteConn {
8477
.to = to,
8578
};
8679
}
@@ -183,7 +176,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
183176
auto deriver = readString(conn->from);
184177
if (deriver != "")
185178
info->deriver = parseStorePath(deriver);
186-
info->references = CommonProto::Serialise<StorePathSet>::read(*this, *conn);
179+
info->references = ServeProto::Serialise<StorePathSet>::read(*this, *conn);
187180
readLongLong(conn->from); // download size
188181
info->narSize = readLongLong(conn->from);
189182

@@ -217,7 +210,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
217210
<< printStorePath(info.path)
218211
<< (info.deriver ? printStorePath(*info.deriver) : "")
219212
<< info.narHash.to_string(Base16, false);
220-
CommonProto::write(*this, *conn, info.references);
213+
ServeProto::write(*this, *conn, info.references);
221214
conn->to
222215
<< info.registrationTime
223216
<< info.narSize
@@ -246,7 +239,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
246239
conn->to
247240
<< exportMagic
248241
<< printStorePath(info.path);
249-
CommonProto::write(*this, *conn, info.references);
242+
ServeProto::write(*this, *conn, info.references);
250243
conn->to
251244
<< (info.deriver ? printStorePath(*info.deriver) : "")
252245
<< 0
@@ -331,7 +324,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
331324
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3)
332325
conn->from >> status.timesBuilt >> status.isNonDeterministic >> status.startTime >> status.stopTime;
333326
if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 6) {
334-
auto builtOutputs = CommonProto::Serialise<DrvOutputs>::read(*this, *conn);
327+
auto builtOutputs = ServeProto::Serialise<DrvOutputs>::read(*this, *conn);
335328
for (auto && [output, realisation] : builtOutputs)
336329
status.builtOutputs.insert_or_assign(
337330
std::move(output.outputName),
@@ -409,10 +402,10 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
409402
conn->to
410403
<< ServeProto::Command::QueryClosure
411404
<< includeOutputs;
412-
CommonProto::write(*this, *conn, paths);
405+
ServeProto::write(*this, *conn, paths);
413406
conn->to.flush();
414407

415-
for (auto & i : CommonProto::Serialise<StorePathSet>::read(*this, *conn))
408+
for (auto & i : ServeProto::Serialise<StorePathSet>::read(*this, *conn))
416409
out.insert(i);
417410
}
418411

@@ -425,10 +418,10 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor
425418
<< ServeProto::Command::QueryValidPaths
426419
<< false // lock
427420
<< maybeSubstitute;
428-
CommonProto::write(*this, *conn, paths);
421+
ServeProto::write(*this, *conn, paths);
429422
conn->to.flush();
430423

431-
return CommonProto::Serialise<StorePathSet>::read(*this, *conn);
424+
return ServeProto::Serialise<StorePathSet>::read(*this, *conn);
432425
}
433426

434427
void connect() override
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
/**
3+
* @file
4+
*
5+
* Template implementations (as opposed to mere declarations).
6+
*
7+
* This file is an exmample of the "impl.hh" pattern. See the
8+
* contributing guide.
9+
*/
10+
11+
#include "serve-protocol.hh"
12+
#include "length-prefixed-protocol-helper.hh"
13+
14+
namespace nix {
15+
16+
/* protocol-agnostic templates */
17+
18+
#define SERVE_USE_LENGTH_PREFIX_SERIALISER(TEMPLATE, T) \
19+
TEMPLATE T ServeProto::Serialise< T >::read(const Store & store, ServeProto::ReadConn conn) \
20+
{ \
21+
return LengthPrefixedProtoHelper<ServeProto, T >::read(store, conn); \
22+
} \
23+
TEMPLATE void ServeProto::Serialise< T >::write(const Store & store, ServeProto::WriteConn conn, const T & t) \
24+
{ \
25+
LengthPrefixedProtoHelper<ServeProto, T >::write(store, conn, t); \
26+
}
27+
28+
SERVE_USE_LENGTH_PREFIX_SERIALISER(template<typename T>, std::vector<T>)
29+
SERVE_USE_LENGTH_PREFIX_SERIALISER(template<typename T>, std::set<T>)
30+
SERVE_USE_LENGTH_PREFIX_SERIALISER(template<typename... Ts>, std::tuple<Ts...>)
31+
32+
#define COMMA_ ,
33+
SERVE_USE_LENGTH_PREFIX_SERIALISER(
34+
template<typename K COMMA_ typename V>,
35+
std::map<K COMMA_ V>)
36+
#undef COMMA_
37+
38+
/**
39+
* Use `CommonProto` where possible.
40+
*/
41+
template<typename T>
42+
struct ServeProto::Serialise
43+
{
44+
static T read(const Store & store, ServeProto::ReadConn conn)
45+
{
46+
return CommonProto::Serialise<T>::read(store,
47+
CommonProto::ReadConn { .from = conn.from });
48+
}
49+
static void write(const Store & store, ServeProto::WriteConn conn, const T & t)
50+
{
51+
CommonProto::Serialise<T>::write(store,
52+
CommonProto::WriteConn { .to = conn.to },
53+
t);
54+
}
55+
};
56+
57+
/* protocol-specific templates */
58+
59+
}

src/libstore/serve-protocol.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "serialise.hh"
2+
#include "util.hh"
3+
#include "path-with-outputs.hh"
4+
#include "store-api.hh"
5+
#include "serve-protocol.hh"
6+
#include "serve-protocol-impl.hh"
7+
#include "archive.hh"
8+
9+
#include <nlohmann/json.hpp>
10+
11+
namespace nix {
12+
13+
/* protocol-specific definitions */
14+
15+
}

src/libstore/serve-protocol.hh

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22
///@file
33

4+
#include "common-protocol.hh"
5+
46
namespace nix {
57

68
#define SERVE_MAGIC_1 0x390c9deb
@@ -10,6 +12,11 @@ namespace nix {
1012
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
1113
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
1214

15+
16+
class Store;
17+
struct Source;
18+
19+
1320
/**
1421
* The "serve protocol", used by ssh:// stores.
1522
*
@@ -22,6 +29,57 @@ struct ServeProto
2229
* Enumeration of all the request types for the protocol.
2330
*/
2431
enum struct Command : uint64_t;
32+
33+
/**
34+
* A unidirectional read connection, to be used by the read half of the
35+
* canonical serializers below.
36+
*
37+
* This currently is just a `Source &`, but more fields will be added
38+
* later.
39+
*/
40+
struct ReadConn {
41+
Source & from;
42+
};
43+
44+
/**
45+
* A unidirectional write connection, to be used by the write half of the
46+
* canonical serializers below.
47+
*
48+
* This currently is just a `Sink &`, but more fields will be added
49+
* later.
50+
*/
51+
struct WriteConn {
52+
Sink & to;
53+
};
54+
55+
/**
56+
* Data type for canonical pairs of serialisers for the serve protocol.
57+
*
58+
* See https://en.cppreference.com/w/cpp/language/adl for the broader
59+
* concept of what is going on here.
60+
*/
61+
template<typename T>
62+
struct Serialise;
63+
// This is the definition of `Serialise` we *want* to put here, but
64+
// do not do so.
65+
//
66+
// See `worker-protocol.hh` for a longer explanation.
67+
#if 0
68+
{
69+
static T read(const Store & store, ReadConn conn);
70+
static void write(const Store & store, WriteConn conn, const T & t);
71+
};
72+
#endif
73+
74+
/**
75+
* Wrapper function around `ServeProto::Serialise<T>::write` that allows us to
76+
* infer the type instead of having to write it down explicitly.
77+
*/
78+
template<typename T>
79+
static void write(const Store & store, WriteConn conn, const T & t)
80+
{
81+
ServeProto::Serialise<T>::write(store, conn, t);
82+
}
2583
};
2684

2785
enum struct ServeProto::Command : uint64_t
@@ -58,4 +116,33 @@ inline std::ostream & operator << (std::ostream & s, ServeProto::Command op)
58116
return s << (uint64_t) op;
59117
}
60118

119+
/**
120+
* Declare a canonical serialiser pair for the worker protocol.
121+
*
122+
* We specialise the struct merely to indicate that we are implementing
123+
* the function for the given type.
124+
*
125+
* Some sort of `template<...>` must be used with the caller for this to
126+
* be legal specialization syntax. See below for what that looks like in
127+
* practice.
128+
*/
129+
#define DECLARE_SERVE_SERIALISER(T) \
130+
struct ServeProto::Serialise< T > \
131+
{ \
132+
static T read(const Store & store, ServeProto::ReadConn conn); \
133+
static void write(const Store & store, ServeProto::WriteConn conn, const T & t); \
134+
};
135+
136+
template<typename T>
137+
DECLARE_SERVE_SERIALISER(std::vector<T>);
138+
template<typename T>
139+
DECLARE_SERVE_SERIALISER(std::set<T>);
140+
template<typename... Ts>
141+
DECLARE_SERVE_SERIALISER(std::tuple<Ts...>);
142+
143+
#define COMMA_ ,
144+
template<typename K, typename V>
145+
DECLARE_SERVE_SERIALISER(std::map<K COMMA_ V>);
146+
#undef COMMA_
147+
61148
}

0 commit comments

Comments
 (0)