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

com.almworks.jira.structure.api.pull.VersionedDataSource Maven / Gradle / Ivy

The newest version!
package com.almworks.jira.structure.api.pull;

import com.atlassian.annotations.PublicApi;
import org.jetbrains.annotations.NotNull;

/**
 * 

{@code VersionedDataSource} establishes a way for sources of some data to version their content, to allow * caching and incremental updates.

* *

Data source uses {@link DataVersion} to tag every internal update of the data. Clients request the updates * to the data through {@link #getUpdate(DataVersion)} method, passing the last version of the data they have seen. * Data source replies with a sub-class of {@link VersionedDataUpdate}, which carries the updated data and * the new version.

* *

A data source may provide incremental updates in case the difference between the state of the data on the * client and in the source can be identified. {@code DataVersion} class enables that through the use of {@code signature} * field, which identifies the sequence (or "version space") for the incremental numeric versions, stored in * the {@code version} field. See {@link DataVersion}.

* *

Pseudo-code for working with {@code VersionedDataSource} would look like this:

* *
 *   VersionedDataSource<MyDataUpdate> source = ...;
 *   DataVersion lastVersionSeen = DataVersion.ZERO;
 *   while (...) {  // this could be event-based or user-initiated periodical updates
 *     MyDataUpdate update = source.getUpdate(lastVersionSeen);
 *     if (update.isEmpty()) {
 *       // usually, do nothing -- nothing has changed, we have the latest version
 *     } else if (update.isFull()) {
 *       // full update -- previous state can be removed, and new state taken fully from the update
 *       ...
 *     } else if (update.isIncremental()) {
 *       // incremental update -- the new state can be produced by taking the difference from the update and applying it to the old state
 *       ...
 *     }
 *     lastVersionSeen = update.getVersion(); // update lastVersionSeen so next time we request updates based on what we have
 *   }
 * 
* *

Of course, the cycle can be replaced with anything else, like polling. It does not have to be periodic, but * the longer time has passed since the update, the less is the chance that incremental update is possible.

* *

Laziness a.k.a. Pull Architecture

* *

An important aspect of most services providing {@code VersionDataSource} is laziness. They are ready to answer * the calls to {@link #getUpdate(DataVersion)}, but if that requires some calculations or getting data from other * sources, those activities get delayed until the moment {@link #getUpdate(DataVersion)} is called. That lets us * keep many data sources, with potentially costly update operations, in memory, and spent resources only on those * that are actually requested by someone.

* *

In the same spirit, data sources can be chained. Say, data source A combines output from data sources B and C. * It subscribes to both B and C and keeps track of the last seen version in both data sources. When it receives * {@code getUpdate()} call, it proceeds to call {@code getUpdate()} from B and C and then combine the result. * Neither data source has to do anything until a user or an active component actually calls {@code A.getUpdate()}.

* * @param type of the data */ @PublicApi public interface VersionedDataSource { /** *

Returns an update based on the version of the data that the client has.

* *

When the caller does not yet have previous state and its version, use {@link DataVersion#ZERO}. Full update * is guaranteed in this case.

* *

If data source depends on other data sources or has pending changes, this call will cause the * source to become up-to-date and perform any necessary calculations.

* * @param fromVersion version of the data that is known to the caller * @return an update that can be applied at the caller site to get the up-to-date state */ @NotNull T getUpdate(@NotNull DataVersion fromVersion); /** *

Returns the current version of the data without triggering data source's recalculation.

* *

This can only be used for diagnostics or similar purposes — * correct continuous update algorithm would use {@link #getUpdate(DataVersion)} only. * There are two reasons for that:

*
    *
  • if you call {@code getCurrentVersion()} and then {@link #getUpdate(DataVersion)}, a concurrent modification * may happen in between, and
  • *
  • if data source needs to do some calculations to come up with a newer version of data, this call will not * trigger it (unlike {@link #getUpdate(DataVersion)}.
  • *
* * @return the most recent version of the data known to the source */ @NotNull DataVersion getCurrentVersion(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy