All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.launchdarkly.sdk.server.interfaces.PersistentDataStore Maven / Gradle / Ivy

There is a newer version: 7.5.0
Show newest version
package com.launchdarkly.sdk.server.interfaces;

import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.DataKind;
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.FullDataSet;
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.KeyedItems;
import com.launchdarkly.sdk.server.interfaces.DataStoreTypes.SerializedItemDescriptor;

import java.io.Closeable;

/**
 * Interface for a data store that holds feature flags and related data in a serialized form.
 * 

* This interface should be used for database integrations, or any other data store * implementation that stores data in some external service. The SDK will take care of * converting between its own internal data model and a serialized string form; the data * store interacts only with the serialized form. The SDK will also provide its own caching * layer on top of the persistent data store; the data store implementation should not * provide caching, but simply do every query or update that the SDK tells it to do. *

* Implementations must be thread-safe. *

* Conceptually, each item in the store is a {@link SerializedItemDescriptor} which always has * a version number, and can represent either a serialized object or a placeholder (tombstone) * for a deleted item. There are two approaches a persistent store implementation can use for * persisting this data: *

* 1. Preferably, it should store the version number and the {@link SerializedItemDescriptor#isDeleted()} * state separately so that the object does not need to be fully deserialized to read them. In * this case, deleted item placeholders can ignore the value of {@link SerializedItemDescriptor#getSerializedItem()} * on writes and can set it to null on reads. The store should never call {@link DataKind#deserialize(String)} * or {@link DataKind#serialize(DataStoreTypes.ItemDescriptor)}. *

* 2. If that isn't possible, then the store should simply persist the exact string from * {@link SerializedItemDescriptor#getSerializedItem()} on writes, and return the persisted * string on reads (returning zero for the version and false for {@link SerializedItemDescriptor#isDeleted()}). * The string is guaranteed to provide the SDK with enough information to infer the version and * the deleted state. On updates, the store must call {@link DataKind#deserialize(String)} in * order to inspect the version number of the existing item if any. *

* Error handling is defined as follows: if any data store operation encounters a database error, or * is otherwise unable to complete its task, it should throw a {@code RuntimeException} to make the SDK * aware of this. The SDK will log the exception and will assume that the data store is now in a * non-operational state; the SDK will then start polling {@link #isStoreAvailable()} to determine * when the store has started working again. * * @since 5.0.0 */ public interface PersistentDataStore extends Closeable { /** * Overwrites the store's contents with a set of items for each collection. *

* All previous data should be discarded, regardless of versioning. *

* The update should be done atomically. If it cannot be done atomically, then the store * must first add or update each item in the same order that they are given in the input * data, and then delete any previously stored items that were not in the input data. * * @param allData a list of {@link DataStoreTypes.DataKind} instances and their corresponding data sets */ void init(FullDataSet allData); /** * Retrieves an item from the specified collection, if available. *

* If the key is not known at all, the method should return null. Otherwise, it should return * a {@link SerializedItemDescriptor} as follows: *

* 1. If the version number and deletion state can be determined without fully deserializing * the item, then the store should set those properties in the {@link SerializedItemDescriptor} * (and can set {@link SerializedItemDescriptor#getSerializedItem()} to null for deleted items). *

* 2. Otherwise, it should simply set {@link SerializedItemDescriptor#getSerializedItem()} to * the exact string that was persisted, and can leave the other properties as zero/false. See * comments on {@link PersistentDataStore} for more about this. * * @param kind specifies which collection to use * @param key the unique key of the item within that collection * @return a versioned item that contains the stored data (or placeholder for deleted data); * null if the key is unknown */ SerializedItemDescriptor get(DataKind kind, String key); /** * Retrieves all items from the specified collection. *

* If the store contains placeholders for deleted items, it should include them in the results, * not filter them out. See {@link #get(DataStoreTypes.DataKind, String)} for how to set the properties of the * {@link SerializedItemDescriptor} for each item. * * @param kind specifies which collection to use * @return a collection of key-value pairs; the ordering is not significant */ KeyedItems getAll(DataKind kind); /** * Updates or inserts an item in the specified collection. *

* If the given key already exists in that collection, the store must check the version number * of the existing item (even if it is a deleted item placeholder); if that version is greater * than or equal to the version of the new item, the update fails and the method returns false. * If the store is not able to determine the version number of an existing item without fully * deserializing the existing item, then it is allowed to call {@link DataKind#deserialize(String)} * for that purpose. *

* If the item's {@link SerializedItemDescriptor#isDeleted()} method returns true, this is a * deleted item placeholder. The store must persist this, rather than simply removing the key * from the store. The SDK will provide a string in {@link SerializedItemDescriptor#getSerializedItem()} * which the store can persist for this purpose; or, if the store is capable of persisting the * version number and deleted state without storing anything else, it should do so. * * @param kind specifies which collection to use * @param key the unique key for the item within that collection * @param item the item to insert or update * @return true if the item was updated; false if it was not updated because the store contains * an equal or greater version */ boolean upsert(DataKind kind, String key, SerializedItemDescriptor item); /** * Returns true if this store has been initialized. *

* In a shared data store, the implementation should be able to detect this state even if * {@link #init} was called in a different process, i.e. it must query the underlying * data store in some way. The method does not need to worry about caching this value; the SDK * will call it rarely. * * @return true if the store has been initialized */ boolean isInitialized(); /** * Tests whether the data store seems to be functioning normally. *

* This should not be a detailed test of different kinds of operations, but just the smallest possible * operation to determine whether (for instance) we can reach the database. *

* Whenever one of the store's other methods throws an exception, the SDK will assume that it may have * become unavailable (e.g. the database connection was lost). The SDK will then call * {@link #isStoreAvailable()} at intervals until it returns true. * * @return true if the underlying data store is reachable */ public boolean isStoreAvailable(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy