When serialising an SDObject with lazy children, populate on-the-fly

* If an object has enoug children, the lazy generator can take multiple seconds
  on e.g. android to fully populate. This is a long enough stall to cause the
  host side to timeout while waiting for the next piece of data. Instead of
  populating everything up front before starting serialising, we now populate as
  we go for each child, so that there's a steadier stream of data and avoid any
  timeouts.
This commit is contained in:
baldurk
2021-06-25 15:51:43 +01:00
parent 6212e9876e
commit b8d7cd17ec
2 changed files with 41 additions and 39 deletions
+6
View File
@@ -375,6 +375,10 @@ private:
friend void DoSerialise(SerialiserType &ser, SDObjectData &el);
template <class SerialiserType>
friend void DoSerialise(SerialiserType &ser, SDObject *el);
template <class SerialiserType>
friend void DoSerialise(SerialiserType &ser, SDObject &el);
template <class SerialiserType>
friend void DoSerialise(SerialiserType &ser, SDChunk &el);
DOCUMENT("A list of :class:`SDObject` containing the children of this :class:`SDObject`.");
mutable StructuredObjectList children;
@@ -932,6 +936,8 @@ private:
friend void DoSerialise(SerialiserType &ser, SDObject &el);
template <class SerialiserType>
friend void DoSerialise(SerialiserType &ser, SDChunk &el);
template <class SerialiserType>
friend void DoSerialise(SerialiserType &ser, SDObject &el, StructuredObjectList &children);
void DeleteLazyGenerator() const
{
+35 -39
View File
@@ -686,53 +686,53 @@ void DoSerialise(SerialiserType &ser, SDObjectPODData &el)
SERIALISE_MEMBER(u);
}
template <class SerialiserType>
void DoSerialise(SerialiserType &ser, StructuredObjectList &el)
{
// since structured objects aren't intended to be exported as nice structured data, only for pure
// transfer purposes, we don't make a proper array here and instead just manually serialise count
// + elements
uint64_t count = el.size();
ser.Serialise("count"_lit, count);
if(ser.IsReading())
el.resize((size_t)count);
for(size_t c = 0; c < (size_t)count; c++)
{
// we also assume that the caller serialising these objects will handle lifetime management.
if(ser.IsReading())
el[c] = new SDObject(""_lit, ""_lit);
ser.Serialise("$el"_lit, *el[c]);
}
}
template <class SerialiserType>
void DoSerialise(SerialiserType &ser, SDObjectData &el)
{
SERIALISE_MEMBER(basic);
SERIALISE_MEMBER(str);
SERIALISE_MEMBER(children);
// this is deliberately not serialised here, it's serialised in the parent SDObject. See below
// SERIALISE_MEMBER(children);
}
template <class SerialiserType>
void DoSerialise(SerialiserType &ser, SDObject &el, StructuredObjectList &children)
{
// serialising the data above doesn't serialise the children, so we can do it here using a
// potential lazy generator. This is so that we don't incur the full cost of populating lazy
// children all at once (which could be slow). This is a bit of a hack as this can take many
// seconds and cause a timeout during transfer, and it would be uglier to try and keep the
// connection alive while serialising chunks.
uint64_t childCount = children.size();
SERIALISE_ELEMENT(childCount).Hidden();
if(ser.IsReading())
children.resize((size_t)childCount);
for(size_t c = 0; c < el.NumChildren(); c++)
{
// we also assume that the caller serialising these objects will handle lifetime management.
if(ser.IsReading())
children[c] = new SDObject(""_lit, ""_lit);
else
el.PopulateChild(c);
ser.Serialise("$el"_lit, *children[c]);
if(ser.IsReading())
children[c]->m_Parent = &el;
}
}
template <class SerialiserType>
void DoSerialise(SerialiserType &ser, SDObject &el)
{
if(ser.IsWriting())
{
el.PopulateAllChildren();
}
SERIALISE_MEMBER(name);
SERIALISE_MEMBER(type);
SERIALISE_MEMBER(data);
if(ser.IsReading())
{
for(size_t i = 0; i < el.NumChildren(); i++)
el.GetChild(i)->m_Parent = &el;
}
DoSerialise(ser, el, el.data.children);
}
template <class SerialiserType>
@@ -740,14 +740,10 @@ void DoSerialise(SerialiserType &ser, SDChunk &el)
{
SERIALISE_MEMBER(name);
SERIALISE_MEMBER(type);
SERIALISE_MEMBER(data);
SERIALISE_MEMBER(metadata);
SERIALISE_MEMBER(data);
if(ser.IsReading())
{
for(size_t i = 0; i < el.NumChildren(); i++)
el.GetChild(i)->m_Parent = &el;
}
DoSerialise(ser, el, el.data.children);
}
INSTANTIATE_SERIALISE_TYPE(SDChunk);