-
Notifications
You must be signed in to change notification settings - Fork 43
channel: truncate twrite messages based on msize #30
channel: truncate twrite messages based on msize #30
Conversation
Current coverage is 15.65% (diff: 0.00%)@@ master #30 diff @@
==========================================
Files 13 13
Lines 1128 1150 +22
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
Hits 180 180
- Misses 900 922 +22
Partials 48 48
|
35052e7
to
d3afddf
Compare
For the Write operation, LGTM. |
@simonferquel let's take it one fix at a time. I placed some todos in there for the read side fixes. Feel free to take those on but it would be good to get a proper bug report characterizing the problem messages. |
From the
Basically, if we truncate, we need to pass through an error. We can still allow the write to occur. I am not sure if we want to rely on the good behavior of writers to ensure this is done correctly. |
} | ||
|
||
type overflowErr struct { | ||
size int // |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing comment?
The |
@justincormack Do you think it is sufficient to return |
d3afddf
to
9c7316b
Compare
@justincormack I've updated the PR accordingly. |
9c7316b
to
7725b53
Compare
I think ErrShortWrite is a good option. We can also provide a io.Writer wrapper that handles the chunking according to ErrShortWrite (so the caller won't have to compute the correct offset for the next chunk). Reads can be fixed in the same fashion, except that io.Reader does not specify that a short read should return a non-nil err. However, we have to make sure we return a correct io.EOF error at some point such that io.ReadFull works correctly even if len(buf) > [length of the actual 9p file - initial offset] with the provided io.Reader wrapper. @stevvooe @justincormack does it make sense to you ? |
io.Reader / io.Writer wrappers could be created by functions like: CreateReaderWriter(session *Session, ctx context.Context, fid Fid, offset int64) *io.ReaderWriter |
This is a basic requirement of an
Typically, I would avoid creating a duplex stream, unless you're trying to implement Also, never use pointers to interfaces. Have you tested this? Can we merge? |
// The truncation is reflected in the return message (Rwrite) by | ||
// the server, so we don't need a return value or error condition | ||
// to communicate it. | ||
msg.Data = msg.Data[:len(msg.Data)-overflow] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
msg seems to be a copy of fcall.Message (I launched test from #31) on this branch with debugging.
adding fcall.Message = msg
fixes the issue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be addressed.
4e1d23f
to
a8d27f2
Compare
a8d27f2
to
c726d66
Compare
@simonferquel This PR should now handle the covered issues, from client and server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost good to merge to me. Will begin work on datakit client today
|
||
// first, craft the shape of the response message | ||
resp := newFcall(fcall.Tag, MessageRread{}) | ||
overflow := uint32(ch.msgmsize(resp)) + msg.Count - uint32(ch.msize) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to compute empty MessageRRead fcall size once at channel initialization to avoid allocating a new fcall each time we do a read transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's take that optimization in a separate PR, with a benchmark.
There is an across the board improvement if we add a field cache to the codec.
func TestWriteOverflow(t *testing.T) { | ||
const ( | ||
msize = 512 | ||
overflowMSize = msize * 3 / 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to cover the case where len(p) fits in msize, but len(p) + [size of envelope] don't to the regression suite. That would avoid some potential naïve (and wrong) optimizations.
func TestTreadRewrite(t *testing.T) { | ||
const ( | ||
msize = 256 | ||
overflowMSize = msize + 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as with writes : I'd like to cover the case where len(p) fits in msize, but len(p) + [size of envelope] don't to the regression suite. That would avoid some potential naïve (and wrong) optimizations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I've clean up these tests. You're welcome to refactoring this one according to the others and create another PR for this one.
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
c726d66
to
a7efa12
Compare
Ok, so the tests have been beefed up quite a bit. If there is anything else needed here, please submit a PR. Let's get this one merged. |
While there are a few problems around handling of msize, the easiest to address and, arguably, the most problematic is that of Twrite. We now truncate Twrite.Data to the correct length if it will overflow the msize limit negotiated on the session. ErrShortWrite is returned by the `Session.Write` method if written data is truncated. In addition, we now reject incoming messages from `ReadFcall` that overflow the msize. Such messages are probably terminal in practice, but can be detected with the `Overflow` function. Tread is also handled accordingly, such that the Count field will be rewritten such that the response doesn't overflow the msize. Signed-off-by: Stephen J Day <stephen.day@docker.com>
a7efa12
to
0f5f58b
Compare
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
Signed-off-by: Simon Ferquel <simon.ferquel@docker.com>
While there are a few problems around handling of msize, the easiest to
address and, arguably, the most problematic is that of Twrite. We now
truncate Twrite.Data to the correct length if it will overflow the msize
limit negotiated on the session.
Other problems with Twrite/Rread are documented in TODOs here, along
with possible solutions.
Signed-off-by: Stephen J Day stephen.day@docker.com