* Make the import operation through the daemon much more efficient
(way fewer roundtrips) by allowing the client to send data in bigger chunks. * Some refactoring.
This commit is contained in:
parent
78598d06f0
commit
e0bd307802
6 changed files with 68 additions and 44 deletions
|
@ -1199,10 +1199,11 @@ struct HashAndReadSource : Source
|
||||||
{
|
{
|
||||||
hashing = true;
|
hashing = true;
|
||||||
}
|
}
|
||||||
virtual void operator () (unsigned char * data, size_t len)
|
size_t read(unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
readSource(data, len);
|
size_t n = readSource.read(data, len);
|
||||||
if (hashing) hashSink(data, len);
|
if (hashing) hashSink(data, n);
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -501,11 +501,11 @@ void RemoteStore::processStderr(Sink * sink, Source * source)
|
||||||
}
|
}
|
||||||
else if (msg == STDERR_READ) {
|
else if (msg == STDERR_READ) {
|
||||||
if (!source) throw Error("no source");
|
if (!source) throw Error("no source");
|
||||||
unsigned int len = readInt(from);
|
size_t len = readInt(from);
|
||||||
unsigned char * buf = new unsigned char[len];
|
unsigned char * buf = new unsigned char[len];
|
||||||
AutoDeleteArray<unsigned char> d(buf);
|
AutoDeleteArray<unsigned char> d(buf);
|
||||||
(*source)(buf, len);
|
size_t n = source->read(buf, len);
|
||||||
writeString(string((const char *) buf, len), to);
|
writeString(string((const char *) buf, n), to); // !!! inefficient
|
||||||
to.flush();
|
to.flush();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace nix {
|
||||||
#define WORKER_MAGIC_1 0x6e697863
|
#define WORKER_MAGIC_1 0x6e697863
|
||||||
#define WORKER_MAGIC_2 0x6478696f
|
#define WORKER_MAGIC_2 0x6478696f
|
||||||
|
|
||||||
#define PROTOCOL_VERSION 0x108
|
#define PROTOCOL_VERSION 0x109
|
||||||
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
|
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
|
||||||
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,9 @@ void BufferedSink::operator () (const unsigned char * data, size_t len)
|
||||||
|
|
||||||
while (len) {
|
while (len) {
|
||||||
/* Optimisation: bypass the buffer if the data exceeds the
|
/* Optimisation: bypass the buffer if the data exceeds the
|
||||||
buffer size and there is no unflushed data. */
|
buffer size. */
|
||||||
if (bufPos == 0 && len >= bufSize) {
|
if (bufPos + len >= bufSize) {
|
||||||
|
flush();
|
||||||
write(data, len);
|
write(data, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -59,29 +60,37 @@ void FdSink::write(const unsigned char * data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Source::operator () (unsigned char * data, size_t len)
|
||||||
|
{
|
||||||
|
while (len) {
|
||||||
|
size_t n = read(data, len);
|
||||||
|
data += n; len -= n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BufferedSource::~BufferedSource()
|
BufferedSource::~BufferedSource()
|
||||||
{
|
{
|
||||||
if (buffer) delete[] buffer;
|
if (buffer) delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BufferedSource::operator () (unsigned char * data, size_t len)
|
size_t BufferedSource::read(unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
if (!buffer) buffer = new unsigned char[bufSize];
|
if (!buffer) buffer = new unsigned char[bufSize];
|
||||||
|
|
||||||
while (len) {
|
if (!bufPosIn) bufPosIn = readUnbuffered(buffer, bufSize);
|
||||||
if (!bufPosIn) bufPosIn = read(buffer, bufSize);
|
|
||||||
|
|
||||||
/* Copy out the data in the buffer. */
|
/* Copy out the data in the buffer. */
|
||||||
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
|
size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len;
|
||||||
memcpy(data, buffer + bufPosOut, n);
|
memcpy(data, buffer + bufPosOut, n);
|
||||||
data += n; bufPosOut += n; len -= n;
|
bufPosOut += n;
|
||||||
if (bufPosIn == bufPosOut) bufPosIn = bufPosOut = 0;
|
if (bufPosIn == bufPosOut) bufPosIn = bufPosOut = 0;
|
||||||
}
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t FdSource::read(unsigned char * data, size_t len)
|
size_t FdSource::readUnbuffered(unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
do {
|
do {
|
||||||
|
@ -94,6 +103,15 @@ size_t FdSource::read(unsigned char * data, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t StringSource::read(unsigned char * data, size_t len)
|
||||||
|
{
|
||||||
|
if (pos == s.size()) throw EndOfFile("end of string reached");
|
||||||
|
size_t n = s.copy((char *) data, len, pos);
|
||||||
|
pos += n;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void writePadding(size_t len, Sink & sink)
|
void writePadding(size_t len, Sink & sink)
|
||||||
{
|
{
|
||||||
if (len % 8) {
|
if (len % 8) {
|
||||||
|
|
|
@ -39,9 +39,14 @@ struct Source
|
||||||
virtual ~Source() { }
|
virtual ~Source() { }
|
||||||
|
|
||||||
/* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
/* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
||||||
It blocks if that much data is not yet available, or throws an
|
It blocks until all the requested data is available, or throws
|
||||||
error if it is not going to be available. */
|
an error if it is not going to be available. */
|
||||||
virtual void operator () (unsigned char * data, size_t len) = 0;
|
void operator () (unsigned char * data, size_t len);
|
||||||
|
|
||||||
|
/* Store up to ‘len’ in the buffer pointed to by ‘data’, and
|
||||||
|
return the number of bytes stored. If blocks until at least
|
||||||
|
one byte is available. */
|
||||||
|
virtual size_t read(unsigned char * data, size_t len) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,12 +60,10 @@ struct BufferedSource : Source
|
||||||
: bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(0) { }
|
: bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(0) { }
|
||||||
~BufferedSource();
|
~BufferedSource();
|
||||||
|
|
||||||
void operator () (unsigned char * data, size_t len);
|
size_t read(unsigned char * data, size_t len);
|
||||||
|
|
||||||
/* Store up to ‘len’ in the buffer pointed to by ‘data’, and
|
/* Underlying read call, to be overriden. */
|
||||||
return the number of bytes stored. If should block until at
|
virtual size_t readUnbuffered(unsigned char * data, size_t len) = 0;
|
||||||
least one byte is available. */
|
|
||||||
virtual size_t read(unsigned char * data, size_t len) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +86,7 @@ struct FdSource : BufferedSource
|
||||||
int fd;
|
int fd;
|
||||||
FdSource() : fd(-1) { }
|
FdSource() : fd(-1) { }
|
||||||
FdSource(int fd) : fd(fd) { }
|
FdSource(int fd) : fd(fd) { }
|
||||||
size_t read(unsigned char * data, size_t len);
|
size_t readUnbuffered(unsigned char * data, size_t len);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,13 +107,7 @@ struct StringSource : Source
|
||||||
const string & s;
|
const string & s;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
StringSource(const string & _s) : s(_s), pos(0) { }
|
StringSource(const string & _s) : s(_s), pos(0) { }
|
||||||
virtual void operator () (unsigned char * data, size_t len)
|
size_t read(unsigned char * data, size_t len);
|
||||||
{
|
|
||||||
s.copy((char *) data, len, pos);
|
|
||||||
pos += len;
|
|
||||||
if (pos > s.size())
|
|
||||||
throw Error("end of string reached");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -210,11 +210,11 @@ struct TunnelSink : Sink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct TunnelSource : Source
|
struct TunnelSource : BufferedSource
|
||||||
{
|
{
|
||||||
Source & from;
|
Source & from;
|
||||||
TunnelSource(Source & from) : from(from) { }
|
TunnelSource(Source & from) : from(from) { }
|
||||||
virtual void operator () (unsigned char * data, size_t len)
|
size_t readUnbuffered(unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
/* Careful: we're going to receive data from the client now,
|
/* Careful: we're going to receive data from the client now,
|
||||||
so we have to disable the SIGPOLL handler. */
|
so we have to disable the SIGPOLL handler. */
|
||||||
|
@ -224,11 +224,16 @@ struct TunnelSource : Source
|
||||||
writeInt(STDERR_READ, to);
|
writeInt(STDERR_READ, to);
|
||||||
writeInt(len, to);
|
writeInt(len, to);
|
||||||
to.flush();
|
to.flush();
|
||||||
string s = readString(from);
|
string s = readString(from); // !!! inefficient
|
||||||
if (s.size() != len) throw Error("not enough data");
|
|
||||||
memcpy(data, (const unsigned char *) s.c_str(), len);
|
|
||||||
|
|
||||||
startWork();
|
startWork();
|
||||||
|
|
||||||
|
if (s.empty()) throw EndOfFile("unexpected end-of-file");
|
||||||
|
if (s.size() > len) throw Error("client sent too much data");
|
||||||
|
|
||||||
|
memcpy(data, (const unsigned char *) s.c_str(), s.size());
|
||||||
|
|
||||||
|
return s.size();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -265,10 +270,11 @@ struct SavingSourceAdapter : Source
|
||||||
Source & orig;
|
Source & orig;
|
||||||
string s;
|
string s;
|
||||||
SavingSourceAdapter(Source & orig) : orig(orig) { }
|
SavingSourceAdapter(Source & orig) : orig(orig) { }
|
||||||
void operator () (unsigned char * data, size_t len)
|
size_t read(unsigned char * data, size_t len)
|
||||||
{
|
{
|
||||||
orig(data, len);
|
size_t n = orig.read(data, len);
|
||||||
s.append((const char *) data, len);
|
s.append((const char *) data, n);
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -397,6 +403,8 @@ static void performOp(unsigned int clientVersion,
|
||||||
|
|
||||||
case wopImportPath: {
|
case wopImportPath: {
|
||||||
startWork();
|
startWork();
|
||||||
|
if (GET_PROTOCOL_MINOR(clientVersion) < 9)
|
||||||
|
throw Error("import not supported; upgrade your client");
|
||||||
TunnelSource source(from);
|
TunnelSource source(from);
|
||||||
Path path = store->importPath(true, source);
|
Path path = store->importPath(true, source);
|
||||||
stopWork();
|
stopWork();
|
||||||
|
|
Loading…
Reference in a new issue