/*
* Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.map.impl.recordstore;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.core.EntryView;
import com.hazelcast.map.impl.MapContainer;
import com.hazelcast.map.impl.MapEntries;
import com.hazelcast.map.impl.iterator.MapEntriesWithCursor;
import com.hazelcast.map.impl.iterator.MapKeysWithCursor;
import com.hazelcast.map.impl.mapstore.MapDataStore;
import com.hazelcast.map.impl.record.Record;
import com.hazelcast.map.impl.record.RecordFactory;
import com.hazelcast.map.merge.MapMergePolicy;
import com.hazelcast.monitor.LocalRecordStoreStats;
import com.hazelcast.nio.serialization.Data;
import com.hazelcast.spi.exception.RetryableHazelcastException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Defines a record-store.
*/
public interface RecordStore<R extends Record> extends LocalRecordStoreStats {
/**
* Default TTL value of a record.
*/
long DEFAULT_TTL = -1L;
String getName();
Object put(Data dataKey, Object dataValue, long ttl);
Object putIfAbsent(Data dataKey, Object value, long ttl);
R putBackup(Data key, Object value);
/**
* @param key the key to be processed.
* @param value the value to be processed.
* @param ttl milliseconds. Check out {@link com.hazelcast.map.impl.proxy.MapProxySupport#putInternal}
* @param putTransient {@code true} if putting transient entry, otherwise {@code false}
* @return previous record if exists otherwise null.
*/
R putBackup(Data key, Object value, long ttl, boolean putTransient);
/**
* Returns {@code true} if key doesn't exist previously, otherwise returns {@code false}.
*
* @see com.hazelcast.core.IMap#set(Object, Object)
*/
boolean set(Data dataKey, Object value, long ttl);
Object remove(Data dataKey);
boolean delete(Data dataKey);
boolean remove(Data dataKey, Object testValue);
/**
* Similar to {@link RecordStore#remove(com.hazelcast.nio.serialization.Data)}
* except removeBackup doesn't touch mapstore since it does not return previous value.
*/
void removeBackup(Data dataKey);
/**
* Gets record from {@link RecordStore}.
* Loads missing keys from map store.
*
* @param dataKey key.
* @param backup <code>true</code> if a backup partition, otherwise <code>false</code>.
* @return value of an entry in {@link RecordStore}
*/
Object get(Data dataKey, boolean backup);
/**
* Called when {@link com.hazelcast.config.MapConfig#isReadBackupData} is <code>true</code> from
* {@link com.hazelcast.map.impl.proxy.MapProxySupport#getInternal}
* <p/>
* Returns corresponding value for key as {@link com.hazelcast.nio.serialization.Data}.
* This adds an extra serialization step. For the reason of this behaviour please see issue 1292 on github.
*
* @param key key to be accessed
* @return value as {@link com.hazelcast.nio.serialization.Data}
* independent of {@link com.hazelcast.config.InMemoryFormat}
*/
Data readBackupData(Data key);
MapEntries getAll(Set<Data> keySet);
boolean containsKey(Data dataKey);
int getLockedEntryCount();
Object replace(Data dataKey, Object update);
/**
* Sets the value to the given updated value
* if {@link com.hazelcast.map.impl.record.RecordFactory#isEquals} comparison
* of current value and expected value is {@code true}.
*
* @param dataKey key which's value is requested to be replaced.
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
boolean replace(Data dataKey, Object expect, Object update);
Object putTransient(Data dataKey, Object value, long ttl);
/**
* Puts key-value pair to map which is the result of a load from map store operation.
*
* @param key key to put.
* @param value to put.
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* @see com.hazelcast.map.impl.operation.PutFromLoadAllOperation
*/
Object putFromLoad(Data key, Object value);
/**
* Puts key-value pair to map which is the result of a load from map store operation on backup.
*
* @param key key to put.
* @param value to put.
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* @see com.hazelcast.map.impl.operation.PutFromLoadAllBackupOperation
*/
Object putFromLoadBackup(Data key, Object value);
/**
* Puts key-value pair to map which is the result of a load from map store operation.
*
* @param key key to put.
* @param value to put.
* @param ttl time to live seconds.
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* @see com.hazelcast.map.impl.operation.PutFromLoadAllOperation
*/
Object putFromLoad(Data key, Object value, long ttl);
boolean merge(Data dataKey, EntryView mergingEntryView, MapMergePolicy mergePolicy);
R getRecord(Data key);
/**
* Puts a data key and a record value to record-store.
* Used in replication operations.
*
* @param key the data key to put record store.
* @param record the value for record store.
* @see com.hazelcast.map.impl.operation.MapReplicationOperation
*/
void putRecord(Data key, R record);
/**
* Iterates over record store entries.
*
* @return read only iterator for map values.
*/
Iterator<Record> iterator();
/**
* Iterates over record store entries by respecting expiration.
*
* @return read only iterator for map values.
*/
Iterator<Record> iterator(long now, boolean backup);
/**
* Fetches specified number of keys from provided tableIndex.
*
* @return {@link MapKeysWithCursor} which is a holder for keys and next index to read from.
*/
MapKeysWithCursor fetchKeys(int tableIndex, int size);
/**
* Fetches specified number of entries from provided tableIndex.
*
* @return {@link MapEntriesWithCursor} which is a holder for entries and next index to read from.
*/
MapEntriesWithCursor fetchEntries(int tableIndex, int size);
/**
* Iterates over record store entries but first waits map store to load.
* If an operation needs to wait a data source load like query operations
* {@link com.hazelcast.core.IMap#keySet(com.hazelcast.query.Predicate)},
* this method can be used to return a read-only iterator.
*
* @param now current time in millis
* @param backup <code>true</code> if a backup partition, otherwise <code>false</code>.
* @return read only iterator for map values.
*/
Iterator<Record> loadAwareIterator(long now, boolean backup);
int size();
boolean txnLock(Data key, String caller, long threadId, long referenceId, long ttl, boolean blockReads);
boolean extendLock(Data key, String caller, long threadId, long ttl);
boolean localLock(Data key, String caller, long threadId, long referenceId, long ttl);
boolean lock(Data key, String caller, long threadId, long referenceId, long ttl);
boolean isLockedBy(Data key, String caller, long threadId);
boolean unlock(Data key, String caller, long threadId, long referenceId);
boolean isLocked(Data key);
boolean isTransactionallyLocked(Data key);
boolean canAcquireLock(Data key, String caller, long threadId);
String getLockOwnerInfo(Data key);
boolean containsValue(Object testValue);
Object evict(Data key, boolean backup);
/**
* Evicts all keys except locked ones.
*
* @param backup <code>true</code> if a backup partition, otherwise <code>false</code>.
* @return number of evicted entries.
*/
int evictAll(boolean backup);
MapContainer getMapContainer();
/**
* @see MapDataStore#softFlush()
*/
long softFlush();
/**
* Clears internal partition data.
*
* @param onShutdown true if {@code close} is called during MapService shutdown,
* false otherwise.
*/
void clearPartition(boolean onShutdown);
/**
* Resets the record store to it's initial state.
*/
void reset();
boolean forceUnlock(Data dataKey);
long getOwnedEntryCost();
boolean isLoaded();
void checkIfLoaded() throws RetryableHazelcastException;
int clear();
boolean isEmpty();
/**
* Do expiration operations.
*
* @param percentage of max expirables according to the record store size.
* @param backup <code>true</code> if a backup partition, otherwise <code>false</code>.
*/
void evictExpiredEntries(int percentage, boolean backup);
/**
* @return <code>true</code> if record store has at least one candidate entry
* for expiration else return <code>false</code>.
*/
boolean isExpirable();
/**
* Checks whether a record is expired or not.
*
* @param record the record from record-store.
* @param now current time in millis
* @param backup <code>true</code> if a backup partition, otherwise <code>false</code>.
* @return <code>true</code> if the record is expired, <code>false</code> otherwise.
*/
boolean isExpired(R record, long now, boolean backup);
/**
* Does post eviction operations like sending events
*
* @param record record to process
* @param backup <code>true</code> if a backup partition, otherwise <code>false</code>.
*/
void doPostEvictionOperations(Record record, boolean backup);
/**
* Loads all given keys from defined map store.
*
* @param keys keys to be loaded.
*/
void loadAllFromStore(List<Data> keys, boolean replaceExistingValues);
void updateLoadStatus(boolean lastBatch, Throwable exception);
MapDataStore<Data, Object> getMapDataStore();
int getPartitionId();
/**
* Returns live record or null if record is already expired. Does not load missing keys from a map store.
*
* @param key key to be accessed
* @return live record or null
* @see #get
*/
R getRecordOrNull(Data key);
/**
* Evicts entries from this record-store.
*
* @param excludedKey this key has lowest priority to be selected for eviction
*/
void evictEntries(Data excludedKey);
/**
* Returns <code>true</code> if eviction is allowed on this record-store, otherwise <code>false</code>
*
* @return <code>true</code> if eviction is allowed on this record-store, otherwise <code>false</code>
*/
boolean shouldEvict();
/**
* Loads all keys and values
*
* @param replaceExistingValues <code>true</code> if need to replace existing values otherwise <code>false</code>
**/
void loadAll(boolean replaceExistingValues);
/**
* Performs initial loading from a MapLoader if it has not been done before
**/
void maybeDoInitialLoad();
Storage createStorage(RecordFactory<R> recordFactory, InMemoryFormat memoryFormat);
Record createRecord(Object value, long ttlMillis, long now);
Record loadRecordOrNull(Data key, boolean backup);
/**
* This can be used to release unused resources.
*/
void disposeDeferredBlocks();
void destroy();
Storage getStorage();
/**
* Starts mapLoader
*/
void startLoading();
/**
* Informs this recordStore about the loading status of the recordStore that this store is migrated from.
* If the 'predecessor' has been loaded this record store should trigger the load again.
* Will be taken into account only if invoked before the startLoading method. Otherwise has no effect.
* <p>
* This method should be deleted when the map's lifecycle has been cleaned-up. Currently it's impossible to
* pass additional state when the record store is created, thus this this state has to be passed in post-creation
* setters which is cumbersome and error-prone.
*/
void setPreMigrationLoadedStatus(boolean loaded);
/**
* Initialize the recordStore after creation
*/
void init();
/**
* @return Returns true if key load has finished, false otherwise.
**/
boolean isKeyLoadFinished();
}