Merge dev/binary-protocol
This replaces the text-based IMAP-like protocol used by clients to communicate with the Akonadi Server by a binary protocol. Compared to text-based protocols de/serializing data from/into a binary stream is much faster and more memory effective. This is mostly because we only malloc the storage and then memcpy the data from the stream to the storage without having to spend CPU cycles on intepreting and parsing the data. Binary protocol requires that both sender and receiver send the data in the exactly same format and order, unlike IMAP where order of arguments did not matter most of the time. To enfore this the Akonadi server provides new Akonadi::Protocol namespace with classes representing each Command/Response specified in the protocol and the (de)serialization is implemented inside these classes. This means that the actual binary-level representation of each command is completely hidden from clients and the server, allowing for changes in the protocol without having to worry about all places where the modified command is parsed or generated by client or server. Although we could technically support multiple versions of the protocol, allowing for mixing versions of server and client libraries the added complexity is not worth it and for that reason both server and client now enforce that they both speak exactly the same version of the protocol. Every change to the (de)serializer code REQUIRES that the protocol version is bumped. Unlike with text-based protocol where unknown keyword can be ignored or missing keyword replaced by default value, with binary protocol inconsistency between serializer and deserializer will lead to data corruption. Finally, each Command in the Protocol has debugString() method that returns a human-readable string representation of the command allowing for easier debugging. The Protocol implementation internally uses custom DataStream class instead of QDataStream, because QDataStream does not handle reading past the end of buffered data. The custom DataStream serializers for common Qt types and containers are based on the original Qt serializers for QDataStream, but simplified (no backwards compatibility with older versions of Qt, no byte-swapping for endianity), but unlike QDataStream the deserializers always call QIODevice::bytesAvailable() to ensure enough data are buffered to succesfully deserialize the data. It will call QIODevice::waitForReadyRead() if not enough data is buffered. This means that deserialization of Protocol Commands is potentially blocking. Some additional changes to the protocol are in order, most notably removing stateful SELECT (permanent collection session context), but those can happen later. We don't have any real benchmarks to objectively measure the performance changes, but subjectively it is faster, best observed on large FETCHes or ItemSyncs.
Please register or sign in to comment