/* * Copyright (c) 2013-2017 Cinchapi 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 com.cinchapi.concourse.server.storage; import java.util.Map; import java.util.Set; import com.cinchapi.concourse.thrift.Operator; import com.cinchapi.concourse.thrift.TObject; /** * <p> * A {@link Store} is a revisioning service that defines primitive operations to * read data from both current and previous states. * </p> * <p> * A {@code Store} can acquire data in one of two ways: directly if it is a * {@link Limbo} or <em>eventually</em> if it is a {@link PermanentStore}. * </p> * <p> * In general, a {@code Limbo} and {@code PermanentStore} work together in a * {@link BufferedStore} to improve write performance by immediately committing * writes into a durable buffer before batch indexing them in the background. * </p> * * @author Jeff Nelson */ public interface Store { /** * Audit {@code record}. * <p> * This method returns a log of revisions in {@code record} as a Map * associating timestamps (in milliseconds) to CAL statements: * </p> * * <pre> * { * "13703523370000" : "ADD 'foo' AS 'bar bang' TO 1", * "13703524350000" : "ADD 'baz' AS '10' TO 1", * "13703526310000" : "REMOVE 'foo' AS 'bar bang' FROM 1" * } * </pre> * * @param record * @return the the revision log */ public Map<Long, String> audit(long record); /** * Audit {@code key} in {@code record} * <p> * This method returns a log of revisions in {@code record} as a Map * associating timestamps (in milliseconds) to CAL statements: * </p> * * <pre> * { * "13703523370000" : "ADD 'foo' AS 'bar bang' TO 1", * "13703524350000" : "ADD 'baz' AS '10' TO 1", * "13703526310000" : "REMOVE 'foo' AS 'bar bang' FROM 1" * } * </pre> * * @param key * @param record * @return the revision log */ public Map<Long, String> audit(String key, long record); /** * Browse {@code key}. * <p> * This method returns a mapping from each of the values that is currently * indexed to {@code key} to a Set the records that contain {@code key} as * the associated value. If there are no such values, an empty Map is * returned. * </p> * * @param key * @return a possibly empty Map of data */ public Map<TObject, Set<Long>> browse(String key); /** * Browse {@code key} at {@code timestamp}. * <p> * This method returns a mapping from each of the values that was indexed to * {@code key} at {@code timestamp} to a Set the records that contained * {@code key} as the associated value at {@code timestamp}. If there were * no such values, an empty Map is returned. * </p> * * @param key * @param timestamp * @return a possibly empty Map of data */ public Map<TObject, Set<Long>> browse(String key, long timestamp); /** * Return a time series that contains the values stored for {@code key} in * {@code record} at each modification timestamp between {@code start} * (inclusive) and {@code end} WITHOUT grabbing any locks. * * This method is ONLY appropriate to call from the methods of * {@link #AtomicOperation} class because in this case intermediate read * {@link #Lock} is not required. * * @param key the field name * @param record the record id * @param start the start timestamp (inclusive) * @param end the end timestamp (exclusive) * @return a {@link Map mapping} from modification timestamp to a non-empty * {@link Set} of values that were contained at that timestamp */ public Map<Long, Set<TObject>> chronologize(String key, long record, long start, long end); /** * Return {@code true} if the store contains any data, present or * historical, for {@code record}. * * @param record * @return {@code true} if the record exists */ public boolean contains(long record); /** * Describe {@code record}. * <p> * This method returns the keys for fields that currently have at least one * mapped value in {@code record} such that {@link #select(String, long)} * for each key is nonempty. If there are no such keys, an empty Set is * returned. * </p> * * @param record * @return a possibly empty Set of keys */ public Set<String> describe(long record); /** * Describe {@code record} at {@code timestamp}. * <p> * This method returns the keys for fields that had at least one mapped * value in {@code record} at {@code timestamp} such that * {@link #select(String, long, long)} for each key at {@code timestamp} is * nonempty. If there are no such keys, an empty Set is returned. * </p> * * @param record * @param timestamp * @return a possibly empty Set of keys */ public Set<String> describe(long record, long timestamp); /** * Explore {@code key} {@code operator} {@code values} at {@code timestamp}. * <p> * This method returns a mapping from the primary key of each record that * meets the criteria at the specified timestamp to the values that caused * the record to meet the criteria. * </p> * * @param key * @param operator * @param values * @return the relevant data for all matching records */ public Map<Long, Set<TObject>> explore(long timestamp, String key, Operator operator, TObject... values); /** * Explore {@code key} {@code operator} {@code values}. * <p> * This method returns a mapping from the primary key of each record that * meets the criteria to the values that cause the record to meet the * criteria. * </p> * * @param key * @param operator * @param values * @return the relevant data for all matching records */ public Map<Long, Set<TObject>> explore(String key, Operator operator, TObject... values); /** * Find {@code key} {@code operator} {@code values} at {@code timestamp}. * <p> * This method returns the records that satisfy {@code operator} in relation * to {@code key} at {@code timestamp} for the appropriate {@code values}. * This is analogous to a SELECT query in a RDBMS. * <p> * * @param timestamp * @param key * @param operator * @param values * @return a possibly empty Set of primary keys */ public Set<Long> find(long timestamp, String key, Operator operator, TObject... values); /** * Find {@code key} {@code operator} {@code values} * <p> * This method will return the records that satisfy {@code operator} in * relation to {@code key} for the appropriate {@code values}. This is * analogous to a SELECT query in a RDBMS. * </p> * * @param key * @param operator * @param values * @return a possibly empty Set of primary keys * @see {@link Operator} */ public Set<Long> find(String key, Operator operator, TObject... values); /** * Return a {@link Set} which contains the ids of every record that has ever * contained data within this {@link Store}. * * @return the {@link Set} of record ids */ public Set<Long> getAllRecords(); /** * Search {@code key} for {@code query}. * <p> * This method performs a fulltext search for {@code query} in all data * <em>currently</em> mapped from {@code key}. * </p> * * @param key * @param query * @return the Set of primary keys identifying the records matching the * search */ public Set<Long> search(String key, String query); /** * Browse {@code record}. * <p> * This method returns a mapping from each of the nonempty keys in * {@code record} to a Set of associated values. If there are no such keys, * an empty Map is returned. * </p> * * @param record * @return a possibly empty Map of data. */ public Map<String, Set<TObject>> select(long record); /** * Browse {@code record} at {@code timestamp}. * <p> * This method returns a mapping from each of the nonempty keys in * {@code record} at {@code timestamp} to a Set of associated values. If * there were no such keys, an empty Map is returned. * </p> * * @param record * @return a possibly empty Map of data. */ public Map<String, Set<TObject>> select(long record, long timestamp); /** * Fetch {@code key} from {@code record}. * <p> * This method returns the values currently mapped from {@code key} in * {@code record}. The returned Set is nonempty if and only if {@code key} * is a member of the Set returned from {@link #describe(long)}. * </p> * * @param key * @param record * @return a possibly empty Set of values */ public Set<TObject> select(String key, long record); /** * Fetch {@code key} from {@code record} at {@code timestamp}. * <p> * This method return the values mapped from {@code key} at * {@code timestamp}. The returned Set is nonempty if and only if * {@code key} is a member of the Set returned from * {@link #describe(long, long)}. * </p> * * @param key * @param record * @param timestamp * @return a possibly empty Set of values */ public Set<TObject> select(String key, long record, long timestamp); /** * Start the service. */ public void start(); /** * Stop the service. */ public void stop(); /** * Verify {@code key} equals {@code value} in {@code record}. * <p> * This method checks that there is <em>currently</em> a mapping from * {@code key} to {@code value} in {@code record}. This method has the same * affect as calling {@link #select(String, long)} * {@link Set#contains(Object)}. * </p> * * @param key * @param value * @param record * @return {@code true} if there is a an association from {@code key} to * {@code value} in {@code record} */ public boolean verify(String key, TObject value, long record); /** * Verify {@code key} equals {@code value} in {@code record} at * {@code timestamp}. * <p> * This method checks that there was a mapping from {@code key} to * {@code value} in {@code record} at {@code timestamp}. This method has the * same affect as calling {@link #select(String, long, DateTime)} * {@link Set#contains(Object)}. * </p> * * @param key * @param value * @param record * @param timestamp * @return {@code true} if there is an association from {@code key} to * {@code value} in {@code record} at {@code timestamp} */ public boolean verify(String key, TObject value, long record, long timestamp); }