Add support for parsing couchbase Flexiable framing#1265
Conversation
e347c2f to
5f04ca3
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1265 +/- ##
==========================================
- Coverage 43.51% 43.44% -0.08%
==========================================
Files 305 304 -1
Lines 32866 32780 -86
==========================================
- Hits 14303 14241 -62
+ Misses 17642 17621 -21
+ Partials 921 918 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
4f55262 to
a8c037c
Compare
| framingExtrasLen = remaining | ||
| } | ||
| if framingExtrasLen > 0 { | ||
| packet.FramingExtras = pkt[offset : offset+framingExtrasLen] |
There was a problem hiding this comment.
do we need some safety checks here?
There was a problem hiding this comment.
+1 maybe also good idea to add some checks on remaining not going < 0?
There was a problem hiding this comment.
Correct me if i am wrong but i think it already checks that remaining can't be under 0
it first sets what we try to read (framingExtrasLen / KeyLen, ...) to be no bigger then remaining, then we check if it is larger then 0 then we read, and continue to the next, then if remaining is smaller then 0 we will stop reading the next variables no?
| } | ||
|
|
||
| // HasFullFramingExtras returns true if the complete framing extras were parsed. | ||
| func (p *Packet) HasFullFramingExtras() bool { |
rafaelroquetto
left a comment
There was a problem hiding this comment.
I have a few concerns - in particular, parsing the binary data with the reader allocates the header every single time (and then copies it around).
Could we instead:
- have ParseHeader to be non-allocating (i.e. return a view of the original data)
- the same for ParsePacket
- if we must store the packets, we can then do a deep-copy on the spot, at least we are cognisant about it
- as a follow up, turn ParsePackets into an iterator-like API (this would do without allocating the slice return value of ParsePackets)
All of this would mean the couchbase parser would be operating directly into the original eBPF buffer memory - no copies, no allocs just views.
The only allocations/copies happening would be the materialisation of CouchBaseInfo - which is fair enough.
| FramingExtrasLen uint8 // Only used for flexible framing (magic 0x08/0x18) | ||
| KeyLen uint16 // For flexible framing, this is only 8 bits but stored as uint16 |
There was a problem hiding this comment.
| FramingExtrasLen uint8 // Only used for flexible framing (magic 0x08/0x18) | |
| KeyLen uint16 // For flexible framing, this is only 8 bits but stored as uint16 | |
| KeyLen uint16 // For flexible framing, this is only 8 bits but stored as uint16 | |
| FramingExtrasLen uint8 // Only used for flexible framing (magic 0x08/0x18) |
| ExtrasLen uint8 | ||
| DataType DataType | ||
| VBucketID uint16 // For requests: VBucket ID; For responses: Status code | ||
| Status Status // Alias for VBucketID when parsing responses |
There was a problem hiding this comment.
wouldn't it make sense to not reuse this, instead declaring a new struct for the response?
The way this is laid out now, it prevents us from reinterpreting binary data into this type (also For requests: VBucket ID; For responses: Status code is detrimental for code readability - the comment is buried in the definition)
There was a problem hiding this comment.
yeah you are right, just seemed like code duplication only for 1 field
but that said it does remove ambiguity so i agree its a good idea
@rafaelroquetto just to make sure i understand correctly, i should make header and packet just a view of the original buffer, and not a stuct containing those fields, and have helper functions to access data for parsing, like: ? |
|
@NimrodAvni78 exactly - that would be awesome. And if for whatever reason you need to "clone" the packet, you can implement a So we end up with an object that is "implicitly shared" (i.e. every copy references the same internal buffer) unless you call "Clone()" (which detaches/returns a copy with a new buffer). This works well for objects whose "getters/methods" are "const" (i.e. they never modify the object state, instead just return some info). Then the object can be initialised from whatever buffer, including the original ebpf buffer (so in this case no copies). |
Checklist
Couchbase packets have an alternative header structure for flexible frames
We were incorrectly parsing these packets and creating a situation where the size of the key looks to big to be included in the packet, hence why we didn't classify the header as valid