Streamline Store swap metadata handling (#1067)
Store swap metadata consists of a handful of Squid-specific TLV fields.
In
69c01cd, fields handling was converted to use lists of TLV objects.
In
528b2c6, the fields were promoted to a hierarchy of C++ classes, each
representing a specific T in TLV, but the transition was not complete:
While trying to add another class to the hierarchy, we discovered that
it would require violating hierarchy design again, adding another XXX.
While trying to address those hierarchy problems, we concluded that the
hierarchy and, in fact, the TLV lists themselves should be removed:
* A class hierarchy with polymorphic methods works well when the same
method can be used regardless of the specific object type. In swap
metadata case, the user code had to know the type (i.e. T in TLV) to
handle each object correctly because only certain types could be
processed at each metadata loading stage. Moreover, some processing
can benefit from using type-specific APIs (e.g., extracting a URL).
Several `switch (type)` statements (and XXXs about doing something a
method should not be doing) illustrate that design conflict.
* A class hierarchy without polymorphic methods can still be useful if
leaf objects can reuse a lot of parent code. However, StoreMeta class
had virtually no code reusable by its derived classes -- it was a
collection of static methods and their equivalents. Metadata leaf
classes were essentially used as global functions.
* Creating a list is useful when the listed objects are traversed/used
multiple times. In swap metadata case, each TLV object is effectively
used once: Official code allocates each object, copies data into it,
and then uses the object either to interpret the just-read value or to
write just-copied bytes into another buffer. The only (minor)
exception to that pattern was when the list was also scanned to
calculate the total buffer size, but that extra scan is unnecessary
and undesirable, especially given modern serialization techniques.
This change converts the problematic StoreMeta class hierarchy into a
few stand-alone functions. The SwapMetaView class implements a view of
the serialized metadata, significantly reducing allocations and copying.
Metadata parser creates a cheap view for the being-parsed field, with
view lifetime confined to that single parsing loop iteration.
Also removed unused STORE_META_* type IDs, addressing several related
XXXs and TODOs. This change was necessary to let the compiler tell us
when we forgot a swap metadata type in a `switch (type)` statement. No
changes to type IDs and their deficient assignment algorithm.
This change attempts to preserve arbitrary metadata validation decisions
that do not violate the overall design, except the following two:
* More problematic Store entries may now be rejected due to conversion
of serious validation errors (e.g., framing problems) to exceptions.
This change decreases the risks of infinite metadata parsing loops and
invalid entry acceptance.
* Some error messages are now logged at level 1 instead of 0.
The Rock-specific ZeroedSlot() check was moved to Rock. Unlike Rock
fixed-size one-file storage, UFS-based cache_dir files are not zeroed.