Search code examples
scalaignite

Ignite collocation between caches with different affinity keys


Let's say I have two tables in separate Ignite caches, A and B with the respective keys:

case class AKey(
    @(QuerySqlField@field) id: Long,
    @(AffinityKeyMapped@field)
    @(QuerySqlField@field) parentId: Long
)

case class BKey(
    @(AffinityKeyMapped@field)
    @(QuerySqlField@field) aId: Long
)

Where A.parentId is a self reference to another entry in table A and B.aId is reference to A.id.

If I want all A entries with the same parentId to be collocated, but I also want all B entries to be collocated with the parentId of the referenced A entry, how would I set up this affinity relationship without including a parentId field in B? Or is this impossible?

It's not clear to me from Ignite's documentation how Ignite establishes an affinity relationship between tables.


Solution

  • How Ignite manages affinity collocation

    Ignite doesn't really establish any "affinity relationship". All it does is mapping of cache keys to affinity keys. All entries in all caches with the same affinity key are guaranteed to be collocated.

    E.g. take caches with the following keys

    class KeyA { int a1; int a2; @AffinityKeyMapped int affKey; }
    class KeyB { int b1; int b2; @AffinityKeyMapped int affKey; }
    

    Here we say that KeyA and KeyB are collocated via affKey - when the values of affKey match, the entries will be collocated. But in fact Ignite has no knowledge of connection between KeyA and KeyB, it processes the tables separately. Only the guarantee that the mapping of affinity key to a node is consistent makes this work. In other words, relation between this caches only exists in our heads and it is our responsibility to ensure that the collocation is correct.

    Solution

    Finally, on your case. It may be surprising but parentId isn't really a good candidate for affinity key. Say we have three values in A

    { id: 1, parentId: 0 }
    { id: 2, parentId: 1 }
    { id: 3, parentId: 2 }
    

    Here one could expect all values to be collocated since all of them are referencing each other in the same "chain". But this is a relationship Ignite doesn't know about. All it knows is that there are three different parentId values - hence, three different affinity keys and no collocation.

    To correctly handle this one has to provide some groupdId that is guaranteed to be the same across all values. A natural fit in your case would be the ID of the root element in the "tree". Then the groupdId will be the @AffinityKeyMapped.

    { id: 1, parentId: 0, groupId: 1 }
    { id: 2, parentId: 1, groupId: 1 }
    { id: 3, parentId: 2, groupId: 1 }
    

    Unfortunately, the second cache has to refer to the exact same value of affinity key, and there is no way to do so without adding that as a field.

    { aId: 2, aGroupId: 1 }
    

    Also, although it isn't related directly to the question, make sure that @AffinityKeyMapped is a part of the cache key, not part of the value - otherwise, it will be ignored.