Serialization
This is a legacy Apache Ignite documentation
The new documentation is hosted here: https://ignite.apache.org/docs/latest/
Specializing BinaryType template
Most user-defined classes going through Ignite C++ API will be passed over the wire to other grid nodes. These classes include cache keys and values.
Passing objects of these classes over wire requires serialization. For Ignite C++ it can be achieved by specializing BinaryType class template for your type:
class Address
{
friend struct ignite::binary::BinaryType<Address>;
public:
Address() { }
Address(const std::string& street, int32_t zip) :
street(street), zip(zip) { }
const std::string& GetStreet() const
{
return street;
}
int32_t GetZip() const
{
return zip;
}
private:
std::string street;
int32_t zip;
};
template<>
struct ignite::binary::BinaryType<Address>
{
static int32_t GetTypeId()
{
return GetBinaryStringHashCode("Address");
}
static void GetTypeName(std::string& name)
{
name = "Address";
}
static int32_t GetFieldId(const char* name)
{
return GetBinaryStringHashCode(name);
}
static bool IsNull(const Address& obj)
{
return obj.GetZip() && !obj.GetStreet().empty();
}
static void GetNull(Address& dst)
{
dst = Address();
}
static void Write(BinaryWriter& writer, const Address& obj)
{
writer.WriteString("street", obj.GetStreet());
writer.WriteInt32("zip", obj.GetZip());
}
static void Read(BinaryReader& reader, Address& dst)
{
dst.street = reader.ReadString("street");
dst.zip = reader.ReadInt32("zip");
}
};
Serialization can be also implemented in raw mode, without field names. This provides the fastest and the most compact serialization, but disables queries:
template<>
struct ignite::binary::BinaryType<Address>
{
static int32_t GetTypeId()
{
return GetBinaryStringHashCode("Address");
}
static void GetTypeName(std::string& name)
{
name = "Address";
}
static int32_t GetFieldId(const char* name)
{
return GetBinaryStringHashCode(name);
}
static bool IsNull(const Address& obj)
{
return false;
}
static void GetNull(Address& dst)
{
dst = Address();
}
static void Write(BinaryWriter& writer, const Address& obj)
{
BinaryRawWriter rawWriter = writer.RawWriter();
rawWriter.WriteString(obj.GetStreet());
rawWriter.WriteInt32(obj.GetZip());
}
static void Read(BinaryReader& reader, Address& dst)
{
BinaryRawReader rawReader = reader.RawReader();
dst.street = rawReader.ReadString();
dst.zip = rawReader.ReadInt32();
}
};
Macros
Ignite C++ defines set of utility macros that could be used to simplify BinaryType specialization. Here is a list of such macros with description:
IGNITE_BINARY_TYPE_START(T)- Start binary type specialization.IGNITE_BINARY_TYPE_END- End binary type specialization.IGNITE_BINARY_GET_TYPE_ID_AS_CONST(id)- Implementation ofGetTypeId()which returns predefined constantid.IGNITE_BINARY_GET_TYPE_ID_AS_HASH(T)- Implementation ofGetTypeId()which returns hash of passed type name.IGNITE_BINARY_GET_TYPE_NAME_AS_IS(T)- Implementation ofGetTypeName()which returns type name as is.IGNITE_BINARY_GET_FIELD_ID_AS_HASH- Default implementation ofGetFieldId()function which returns Java-way hash code of the string.IGNITE_BINARY_IS_NULL_FALSE(T)- Implementation ofIsNull()function which always returnsfalse.IGNITE_BINARY_IS_NULL_IF_NULLPTR(T)- Implementation ofIsNull()function which returntrueif passed object is null pointer.IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(T)- Implementation ofGetNull()function which returns an instance created with default constructor.IGNITE_BINARY_GET_NULL_NULLPTR(T)- Implementation of GetNull() function which returnsNULLpointer.
So we can describe Address class declared above using these macros as follows:
namespace ignite
{
namespace binary
{
IGNITE_BINARY_TYPE_START(Address)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(Address)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(Address)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(Address)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
static bool IsNull(const Address& obj)
{
return obj.GetZip() == 0 && !obj.GetStreet().empty();
}
static void Write(BinaryWriter& writer, const Address& obj)
{
writer.WriteString("street", obj.GetStreet());
writer.WriteInt32("zip", obj.GetZip());
}
static void Read(BinaryReader& reader, Address& dst)
{
dst.street = reader.ReadString("street");
dst.zip = reader.ReadInt32("zip");
}
IGNITE_BINARY_TYPE_END
}
}
Reading and Writing Values
There are several approaches for writing and reading data. The first way is to use an object's value directly:
CustomType val;
// some application code here
// ...
writer.WriteObject<CustomType>("field_name", val);
CustomType val = reader.ReadObject<CustomType>("field_name");
The second approach does the same but uses a pointer to the object:
// Writing null to as a value for integer field.
writer.WriteObject<int32_t*>("int_field_name", nullptr);
// Writing a value of the custom type by pointer.
CustomType *val;
// some application code here
// ...
writer.WriteObject<CustomType*>("field_name", val);
// Reading value which can be null.
CustomType* nullableVal = reader.ReadObject<CustomType*>("field_name");
if (nullableVal) {
// ...
}
// You can use a smart pointer as well.
std::unique_ptr<CustomType> nullablePtr = reader.ReadObject<CustomType*>();
if (nullablePtr) {
// ...
}
An advantage of the pointer-based technique is that it allows writing or reading null as a value.
Updated about 5 years ago
