View Source FDBC.Tuple.Versionstamp (fdbc v0.1.0)

Used to represent values written by versionstamp operations within the tuple layer. This wraps a binary of length 12 that can be used to represent some global order of items within the database.

These versions are composed of two separate components:

  1. the 10-byte tr version.
  2. the two-byte user version.

The tr version is set by the database, and it is used to impose an order between different transactions. This order is guaranteed to be monotonically increasing over time for a given database. In particular, it imposes an order that is consistent with a serialization order of the database’s transactions. If the client elects to leave the tr version as its default value of nil, then the Versionstamp is considered 'incomplete'. This will cause the first 10 bytes of the serialized FDBC.Tuple.Versionstamp to be filled in with dummy bytes when serialized. When used with operations :set_versionstamped_key or :set_versionstamped_value in FDBC.Transaction.atomic_op/4, an incomplete version can be used to ensure that a key gets written with the current transaction’s version which can be useful for maintaining append-only data structures within the database. If the tr version is set to something that is not nil, it should be set to a binary of length 10. In this case, the Versionstamp is considered 'complete'. This is the usual case when one reads a serialized FDBC.Tuple.Versionstamp from the database.

The user version should be specified as an integer, but it must fit within a two-byte unsigned integer. It is set by the client, and it is used to impose an order between items serialized within a single transaction. If left unset, then final two bytes of the serialized FDBC.Tuple.Versionstamp are filled in with a default constant value.

The example belows shows how to serialize an incomplete FDBC.Tuple.Versionstamp, write it to the database and then read it back:

defmodule Example do
  def read_versionstamp(db, subspace) do
    FDBC.transact(db, fn tr ->
      {start, stop} = FDBC.Subspace.range(subspace)
      case FDBC.Transaction.get_range(tr, start, stop, limit: 1) do
        [] -> nil
        [{k, _}] -> FDBC.Subspace.unpack(k)
      end
    end)
  end

  def write_versionstamp(db, subspace) do
    FDBC.transact(db, fn tr ->
      key = FDBC.Subspace.pack(subspace, [Versionstamp.new()])
      :ok = FDBC.Transaction.atomic_op(tr, :set_versionstamped_key, key, <<>>)
      FDBC.Transaction.async_get_versionstamp(tr)
    end) |> FDBC.Future.resolve()
  end
end

db = FDBC.Database.create()
subspace = FDBC.Subspace.new(['prefix'])
{start, stop} = FDBC.Subspace.range(subspace)
:ok = FDBC.Transaction.clear_range(db, start, stop)
version = Example.write_versionstamp(db, subspace)
v = Example.read_versionstamp(db, subspace)
assert v == FDBC.Tuple.Versionstamp(tr=version)

Summary

Functions

Converts a versiontamp into its binary representation.

Checks if a versionstamp is incomplete.

Loads a versionstamp from its binary representation.

Create a versionstamp.

Types

t()

@type t() :: %FDBC.Tuple.Versionstamp{tr: binary(), user: integer()}

Functions

dump(versionstamp)

@spec dump(t()) :: binary()

Converts a versiontamp into its binary representation.

incomplete?(versionstamp)

@spec incomplete?(t()) :: boolean()

Checks if a versionstamp is incomplete.

load(arg)

@spec load(binary()) :: t()

Loads a versionstamp from its binary representation.

new(tr \\ nil, user \\ 0)

@spec new(binary() | nil, integer()) :: t()

Create a versionstamp.

Where tr is the transaction version that is set by the database and user is the client specified version used to impose an order between items serialized within a single transaction.

If tr is nil then an incomplete versionstamp is created.