View Source EctoFoundationDB.Tenant (Ecto.Adapters.FoundationDB v0.4.0)

This module allows the application to create, open, and delete tenants within the FoundationDB database. All transactions require a tenant, so any application that uses the Ecto FoundationDB Adapter must use this module.

EctoFoundationDB supports 2 different backends for the Tenant implementation:

  1. EctoFoundationDB.Tenant.DirectoryTenant: The default. Tenants are managed via the :erlfdb_directory layer. Each tenant is assigned a byte prefix. EctoFDB puts that prefix as the first element of every tuple key. If your application wishes to write keys directly to the database, it must also respect this prefix.
  2. EctoFoundationDB.Tenant.ManagedTenant: Uses the experimental FoundationDB Tenants. This requires tenant_mode=required_experimental or tenant_mode=optional_experimental to be enabled on your FDB system. EctoFDB does not need to prefix keys because it happens automatically at the FDB transaction level. If your application wishes to write keys directory to the database, there is no prefix to worry about. Use caution: FDB Tenants are not yet tested with the same rigor as the rest of FDB.

If you wish to use the experimental ManagedTenant, add this option to your Repo config:

config :my_app, MyApp.Repo,
  tenant_backend: EctoFoundationDB.Tenant.ManagedTenant

EctoFDB does not support switching between tenant backends on a database. If you want to switch backend, you must use a new empty database.

Summary

Functions

Clear all data for the given tenant. This cannot be undone.

Clears data in a tenant and then deletes it. If the tenant doesn't exist, no-op.

Create a tenant in the database.

Deletes a tenant from the database permanently. The tenant must have no data.

Returns true if the tenant already exists in the database.

List all tenants in the database. Could be expensive.

Open a tenant with a repo. With the result returned by this function, the caller can do database operations on the tenant's portion of the key-value store.

Open a tenant. With the result returned by this function, the caller can do database operations on the tenant's portion of the key-value store.

Helper function to ensure the given tenant exists and then clear it of all data, and finally return an open handle. Useful in test code, but in production, this would be dangerous.

Packs an Elixir tuple into an FDB-encoded Tuple.

Types

@type id() :: :erlfdb.tenant_name()
@type prefix() :: String.t()
@type t() :: %EctoFoundationDB.Tenant{
  backend: term(),
  id: term(),
  meta: term(),
  ref: term(),
  txobj: term()
}

Functions

@spec clear(Ecto.Repo.t(), id()) :: :ok

Clear all data for the given tenant. This cannot be undone.

@spec clear_delete!(Ecto.Repo.t(), id()) :: :ok

Clears data in a tenant and then deletes it. If the tenant doesn't exist, no-op.

@spec create(Ecto.Repo.t(), id()) :: :ok

Create a tenant in the database.

@spec delete(Ecto.Repo.t(), id()) :: :ok

Deletes a tenant from the database permanently. The tenant must have no data.

@spec exists?(Ecto.Repo.t(), id()) :: boolean()

Returns true if the tenant already exists in the database.

@spec list(Ecto.Repo.t()) :: [id()]

List all tenants in the database. Could be expensive.

Link to this function

open(repo, id, options \\ [])

View Source
@spec open(Ecto.Repo.t(), id(), EctoFoundationDB.Options.t()) :: t()

Open a tenant with a repo. With the result returned by this function, the caller can do database operations on the tenant's portion of the key-value store.

The tenant must already exist.

When opening tenants with a repo, all migrations are automatically performed. This can cause open/2 to take a significant amount of time. Tenants can be kept open indefinitely, with any number of database transactions issued upon them.

Link to this function

open!(repo, id, options \\ [])

View Source
@spec open!(Ecto.Repo.t(), id(), EctoFoundationDB.Options.t()) :: t()

Open a tenant. With the result returned by this function, the caller can do database operations on the tenant's portion of the key-value store.

If the tenant does not exist, it is created.

When opening tenants with a repo, all migrations are automatically performed. This can cause open/2 to take a significant amount of time. Tenants can be kept open indefinitely, with any number of database transactions issued upon them.

Link to this function

open_empty!(repo, id, options_in \\ [])

View Source
@spec open_empty!(Ecto.Repo.t(), id(), EctoFoundationDB.Options.t()) :: t()

Helper function to ensure the given tenant exists and then clear it of all data, and finally return an open handle. Useful in test code, but in production, this would be dangerous.

Packs an Elixir tuple into an FDB-encoded Tuple.

Keyspace Design

We always pack into a non-prefixed tuple key. In other words, EctoFDB DirectoryTenant keys use the subspace prefix as the first tuple element instead of binary key prefix. As such, our keys are not compliant with other Directory Layer implementations. However, we've made this choice so that we can continue to use GetMappedRange functionality. (Indeed, the GetMappedRange mapper spec has reserved syntax for stripping out non-tuple prefixes, but it's not yet implemented.) Note: ManagedTenant keys do not use directories/subspaces. The underlying binary prefix that a ManagedTenant uses internally still allows use of GetMappedRange.

ManagedTenants and GetMappedRange are both experimental features. The safest choice is to use neither, but that would forfeit the GetMappedRange optimization. We choose to accept the risk of GetMappedRange, which can easily be replaced with a different client implementation, and suggest against using ManagedTenant because it puts your data at risk with its unsupported[0][1] keyspace.

Link to this function

primary_codec(tenant, tuple)

View Source