/* * Copyright Terracotta, Inc. * * Licensed 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.ehcache.clustered.common.internal.store; import java.nio.ByteBuffer; import java.util.concurrent.TimeoutException; /** * Defines Server Side data structure for storing * cache data. * This is conceptually a multi-map which has hash as the key * and a {@link Chain} as the mapping * Chain is list of {@link Element}s such that the same key has * multiple mappings attached. * * Physical representation looks something like this : * * hash -> |payLoad1| - |payLoad2| - |payLoad3| * hash -> |payLoad1| - |payLoad2| * * This only allows append & replaceAtHead operations rather than * normal map operations. * */ public interface ServerStore { /** * Returns the Chain associated with the provided hash. * An empty Chain if no mapping exists. * * @param key hashcode of the key * @return the {@link Chain} associated with the hash * * @throws TimeoutException if the get exceeds the timeout configured for read operations */ Chain get(long key) throws TimeoutException; /** * Appends the provided binary to Chain associated with key atomically. * While appending, the payLoad is stored in {@link Element}. * Note that the {@code payLoad}'s position and limit are left untouched. * * @param key to which the payLoad has to be appended * @param payLoad to be appended * * @throws TimeoutException if the append exceeds the timeout configured for mutative operations */ void append(long key, ByteBuffer payLoad) throws TimeoutException; /** * The Chain associated with key, previous to append is returned. * An empty Chain if no mapping existed previously. * The operation atomically appends payLoad and returns the previously associated Chain * with the key. * Following block of instructions are atomically performed. * { * Chain prevChain = get(key); * append(key, payLoad); * return prevChain; * } * Note that the {@code payLoad}'s position and limit are left untouched. * * @param key to which the payLoad has to be appended * @param payLoad to be appended * @return the Chain associated with the key before payLoad was appended * * @throws TimeoutException if the get exceeds the timeout configured for read operations */ Chain getAndAppend(long key, ByteBuffer payLoad) throws TimeoutException; /** * Replaces the provided Chain with the equivalent Chain present at the head. * This operation is not guaranteed to succeed. * The replaceAtHead is successful iff the Chain associated with the key has * a sub-sequence of elements present as expected.. * * If below mapping is present: * * hash -> |payLoadA| - |payLoadB| - |payLoadC| * * And replaceAtHead(hash, |payLoadA| - |payLoadB| - |payLoadC|, |payLoadC'|) is invoked * then this operation will succeed & the final mapping would be: * * hash -> |payLoadC'| * * The same operation will also succeed if the mapping was modified by the time replace was invoked to * * hash -> |payLoadA| - |payLoadB| - |payLoadC| - |payLoadD| * * Though the final mapping would be: * * hash -> |payLoadC'| - |payLoadD| * * Failure case: * * But before replaceAtHead if it was modified to : * * hash -> |payLoadC"| - |payLoadD| * * then replaceAtHead(hash, |payLoadA| - |payLoadB| - |payLoadC|, |payLoadC'|) will be ignored. * Note that the payload's position and limit of all elements of both chains are left untouched. * * @param key for which Chain has to be replaced * @param expect of the original Chain which this operation intends to replaceAtHead * @param update the new Chain to be replaced */ void replaceAtHead(long key, Chain expect, Chain update); /** * Removes all the mappings from this store. But this operation is not atomic. * If appends are happening in parallel, this operation does not guarantee an * empty store on the completion of this operation. * * @throws TimeoutException if the get exceeds the timeout configured for mutative operations */ void clear() throws TimeoutException; }