/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.cache.affinity; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.concurrent.Callable; /** * Optional annotation to specify custom key-to-node affinity. Affinity key is a key * which will be used to determine a node on which given cache key will be stored. This * annotation allows to mark a field in the cache key object that will be * used as an affinity key (instead of the entire cache key object that is used for * affinity by default). Note that a class can have only one field annotated * with {@code @AffinityKeyMapped} annotation. * <p> * One of the major use cases for this annotation is the routing of grid computations * to the nodes where the data for this computation is cached, the concept * otherwise known as {@code Collocation Of Computations And Data}. * <p> * <h1 class="header">Mapping Cache Keys</h1> * The default implementation of {@link AffinityKeyMapper}, which will be used * if no explicit affinity mapper is specified in cache configuration, will first look * for any field annotated with {@code @AffinityKeyMapped} annotation. * If such field is not found, then the cache key itself will be used for * key-to-node affinity (this means that all objects with the same cache key will always * be routed to the same node). If such field is found, then the value of this * field will be used for key-to-node affinity. This allows to specify alternate * affinity key, other than the cache key itself, whenever needed. * <p> * For example, if a {@code Person} object is always accessed together with a {@code Company} object * for which this person is an employee, then for better performance and scalability it makes sense to * collocate {@code Person} objects together with their {@code Company} object when storing them in * cache. To achieve that, cache key used to cache {@code Person} objects should have a field or method * annotated with {@code @AffinityKeyMapped} annotation, which will provide the value of * the company key for which that person works, like so: * <pre name="code" class="java"> * public class PersonKey { * // Person ID used to identify a person. * private String personId; * * // Company ID which will be used for affinity. * @AffinityKeyMapped * private String companyId; * ... * } * ... * // Instantiate person keys. * Object personKey1 = new PersonKey("myPersonId1", "myCompanyId"); * Object personKey2 = new PersonKey("myPersonId2", "myCompanyId"); * * // Both, the company and the person objects will be cached on the same node. * cache.put("myCompanyId", new Company(..)); * cache.put(personKey1, new Person(..)); * cache.put(personKey2, new Person(..)); * </pre> * <p> * <h2 class="header">AffinityKey</h2> * For convenience, you can also optionally use {@link AffinityKey} class. Here is how a * {@code PersonKey} defined above would look using {@link AffinityKey}: * <pre name="code" class="java"> * Object personKey1 = new AffinityKey("myPersonId1", "myCompanyId"); * Object personKey2 = new AffinityKey("myPersonId2", "myCompanyId"); * * // Both, the company and the person objects will be cached on the same node. * cache.put(myCompanyId, new Company(..)); * cache.put(personKey1, new Person(..)); * cache.put(personKey2, new Person(..)); * </pre> * <p> * <h1 class="header">Collocating Computations And Data</h1> * It is also possible to route computations to the nodes where the data is cached. This concept * is otherwise known as {@code Collocation Of Computations And Data}. In this case, * {@code @AffinityKeyMapped} annotation allows to specify a routing affinity key for a * {@link org.apache.ignite.compute.ComputeJob} or any other grid computation, such as {@link Runnable}, * {@link Callable}, or {@link org.apache.ignite.lang.IgniteClosure}. It should be attached to a method or * field that provides affinity key for the computation. Only one annotation per class is allowed. * Whenever such annotation is detected, then {@link org.apache.ignite.spi.loadbalancing.LoadBalancingSpi} * will be bypassed, and computation will be routed to the grid node where the specified affinity key is cached. * <p> * For more information about cache affinity also see {@link AffinityKeyMapper} and * {@link AffinityFunction} documentation. * Affinity for a key can be found from any node, regardless of whether it has cache started * or not. If cache is not started, affinity function will be fetched from the remote node * which does have the cache running. * * @see AffinityFunction * @see AffinityKeyMapper * @see AffinityKey */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface AffinityKeyMapped { // No-op. }