Skip to content

Create optimized Fressian handlers for tokens and elements #260

Open
@WilliamParker

Description

@WilliamParker

Currently Clara elements and tokens use a general Fressian handler for arbitrary Clojure records. This works, but is likely suboptimal for performance. This includes both things that impact records in general and things specific to elements and tokens due to the structure of their contents. Due to the sheer number of tokens and elements that can exist in large rules sessions I believe these optimizations have the potential to significantly improve performance of the Fressian durability implementation.

  1. Since the handler is built for arbitrary record types, it has to serialize the record with the name of its constructor function as seen here. After deserialization, this name is then used as a symbol to resolve the function. We've seen these calls to clojure.core/resolve be a hotspot during session deserialization. Furthermore, the function name obviously takes up space in the serialized session.
  2. Since the record is serialized as an arbitrary map here we have to serialize the keys, which takes space in the serialized session although probably not much since they are cached. Deserializing the keys takes time as well. Furthermore, when reading the record we create a map of the contents that are then passed to the constructor function here. Since this map is not used once the record is created, it would be more efficient to use something that could call the token or element's positional constructor without needing to build this map.
  3. We know that we don't use metadata on tokens or elements but we still serialize and deserialize an empty map for them.
  4. There are places where we it may make sense to use caching with an InternalMemIdx marker on structures where it doesn't make sense in general for records. In particular, many of the tuples inside the :matches of tokens can be expected to be identical to other such tuples due to the many places in the engine where we take the existing vector of :matches and conj on a new one to build a new token, such as here. Bindings maps could benefit in some cases as well, although probably not as much as token match tuples. For example, RootJoinNode just takes a binding map from an element and uses it in a token here.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions