Documentation
¶
Overview ¶
Package cache mirrors the name contracts in Mongo (see "Name cache" in the README).
Index ¶
Constants ¶
const CName = "any-ns.cache"
Variables ¶
var ErrDuplicateNames = errors.New("the cache has duplicates of a name: resolve them by hand, then create the unique index (-dedupe-cache -refresh-apply)")
ErrDuplicateNames is returned by VerifyNameIndex when the unique index is missing and the cache has more than one record of a name: they must be resolved by hand before it can be created
var ErrIncompleteRecords = errors.New("the cache has incomplete records (no owner): refresh them first (-refresh-cache -refresh-apply), then purge")
ErrIncompleteRecords is returned by PurgeTombstones while the cache has incomplete records without an owner: a node older than GO-7567 would serve them without the owner forever. refresh them first (-refresh-cache -refresh-apply, or the background repair)
var ErrNameDataIncomplete = errors.New("name is registered, but its owner could not be read")
ErrNameDataIncomplete is returned by UpdateInCache when the registry confirmed the name (it is registered and not lapsed), but its owner could not be read. the confirmed part is cached and the record is marked refresh_needed, so lookups keep reporting the name as taken
var ErrNameIndexNotUnique = fmt.Errorf("the name cache has a non-unique index on {name: 1}: drop it by hand, " +
"resolve the duplicates, then run -dedupe-cache -refresh-apply")
ErrNameIndexNotUnique is returned when there is an index on exactly {name: 1}, but it is not unique. it is never dropped automatically (an operator decides)
var ErrNameNotRegistered = errors.New("name is not registered")
ErrNameNotRegistered is returned by UpdateInCache when the registry has no owner for the name (or it has lapsed): the cache does not have it as a taken name. it is not a transport error: callers should treat it as "not registered (yet)", never as "the cache is up to date"
Functions ¶
func NewMaintainer ¶ added in v0.7.0
NewMaintainer is the cache for a one-off maintenance run (a Maintainer): it does not touch the indexes at start (VerifyNameIndex reports them) and runs no background refresh
Types ¶
type AliasStats ¶ added in v0.7.0
type AliasStats struct {
// records under a non-canonical spelling
Aliases int
// renamed to the canonical name (there was no canonical record), kept as they are, marked
// for a refresh
Renamed int
// deleted: the canonical record has its block, is live, complete and at least as new
Deleted int
// records given their canonical spelling (canon), aliases and canonical records alike
Canon int
// left as they are (the canonical record has no block, is a tombstone, incomplete or older),
// the canonical record marked for a refresh: for an operator, or a later run
Kept []string
}
AliasStats is what MigrateAliases did (or would do, in a dry run)
type CacheService ¶
type CacheService interface {
// call it before you want to check in smart contracts
// it will look up data in Mongo.
// a cached name is always reported as taken: only the contracts can prove that a name is
// available again, then the record becomes a tombstone (see UpdateInCache)
IsNameAvailable(ctx context.Context, in *nsp.NameAvailableRequest) (out *nsp.NameAvailableResponse, err error)
GetNameByAddress(ctx context.Context, in *nsp.NameByAddressRequest) (out *nsp.NameByAddressResponse, err error)
GetNameByAnyId(ctx context.Context, in *nsp.NameByAnyIdRequest) (out *nsp.NameByAddressResponse, err error)
// call it when you need to read REAL data: smart contracts -> cache
// will return no error if name is found and data was updated
// will return ErrNameNotRegistered if the registry has no owner for the name, or if the
// name has lapsed (nameExpires + grace period has passed, it can be registered again).
// that is an expected answer, not a failure: the cache does not have the name as taken
// (a cached record becomes a tombstone only when a finalized block confirms it, until then
// it stays as it is), so callers must never treat it as "the cache is up to date"
// will return ErrNameDataIncomplete if the name is registered, but its owner could not be
// read: the cache has it as taken, without the owner (see ErrNameDataIncomplete)
// will return any other error if something went wrong
UpdateInCache(ctx context.Context, in *nsp.NameAvailableRequest) (err error)
// UpdateInCacheAfterOperation is UpdateInCache for a name that a completed operation changed:
// the same refresh at the latest block, and it schedules re-reads of the name (see
// rereadDelays) in the same write, to pick up a lagging provider or a reorg
UpdateInCacheAfterOperation(ctx context.Context, in *nsp.NameAvailableRequest) (err error)
// RefreshAfterOperation hands a name that a completed operation changed to the background:
// its re-reads are stored on its record (durable: a dropped request or a restart does not lose
// them), and a refresh at the latest block runs (if it fails, the record is marked
// refresh_needed). it never blocks and never waits for a write
RefreshAfterOperation(fullName string)
app.Component
}
type Maintainer ¶ added in v0.7.0
type Maintainer interface {
// RefreshAll re-reads every cached name (tombstones too) from the contracts, with the same
// decisions as the node (finality for a removal, the order of the records).
// apply == false is a dry run: it decides the same, but writes nothing.
// interval is the delay between two names, every name costs several contract calls
RefreshAll(ctx context.Context, apply bool, interval time.Duration) (RefreshStats, error)
// VerifyNameIndex checks the unique index on {name: 1}: any unique one is accepted whatever
// its name (prod has name_1). a missing one is created with apply (it fails if the cache has
// duplicates of a name: they are never resolved automatically). a non-unique one is an error
// (ErrNameIndexNotUnique), it is never dropped
VerifyNameIndex(ctx context.Context, apply bool) (NameIndexStats, error)
// MigrateAliases resolves the records cached under a non-canonical spelling (see alias.go),
// one transaction per record: no canonical record -> the alias is renamed to the canonical
// name (its data kept, marked for a refresh); the canonical record is live, complete and at
// least as new -> the alias is deleted; otherwise both stay (Kept). apply == false is a dry run
MigrateAliases(ctx context.Context, apply bool) (AliasStats, error)
// PurgeTombstones prepares the cache for a rollback to a version older than GO-7567: such a
// node reads ANY record of a name as a taken name, a tombstone too. it deletes the
// tombstones. it refuses to run while the cache has incomplete records without an owner
// (ErrIncompleteRecords, PurgeStats.Incomplete names them): an old node would serve them
// without the owner and never repair them. apply == false is a dry run: it only counts
PurgeTombstones(ctx context.Context, apply bool) (PurgeStats, error)
}
Maintainer holds the cache maintenance tools (the -refresh-cache, -dedupe-cache and -purge-tombstones flags of the node). it is not a part of CacheService
type NameDataItem ¶
type NameDataItem struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
FullName string `bson:"name"`
// always store in LOWER CASE!
OwnerEthAddress string `bson:"owner_eth_address"`
OwnerScwEthAddress string `bson:"owner_scw_eth_address"`
OwnerAnyAddress string `bson:"owner_any_address"`
SpaceId string `bson:"space_id"`
NameExpires int64 `bson:"name_expires"`
// the block the contracts were read at (all the reads of a refresh by its hash).
// 0 for records written before it was added
ObservedBlock int64 `bson:"observed_block,omitempty"`
ObservedBlockHash string `bson:"observed_block_hash,omitempty"`
// that block's timestamp (unix seconds): lapse decisions use it, not the local clock
ObservedBlockTime int64 `bson:"observed_block_time,omitempty"`
// the local time of the read (unix ms)
ObservedAt int64 `bson:"observed_at,omitempty"`
// the latest read (unix ms) of this record's fork (block and hash), if a later one than
// ObservedAt: a read that lost to this record (e.g. an incomplete one) still counts for
// which fork was read last (see newer)
ForkReadAt int64 `bson:"fork_read_at,omitempty"`
// no background refresh takes the record before this (unix ms): a refresh in progress (a
// lease) or a failed one (a backoff)
RefreshNextAt int64 `bson:"refresh_next_at,omitempty"`
// when the periodic scan takes the record (unix ms, see repairAt). indexed
RepairAt int64 `bson:"repair_at,omitempty"`
// scheduled re-reads of the record (unix ms, sorted): after a completed operation, see
// rereadDelays. a read after one of them is done with it
Rereads []int64 `bson:"rereads,omitempty"`
// a tombstone: the name is not registered (or has lapsed) at ObservedBlock, a finalized
// block. it keeps the block, so that an older read can not bring the name back. lookups
// serve it as "not in the cache"
Removed bool `bson:"removed,omitempty"`
// the registry confirmed the name, but the enrichment (owner, AnyID, space ID) failed: the
// record holds what was confirmed, and what it could carry over from the previous record
// (see carryOver). this is what orders two records of one block (see newer)
Incomplete bool `bson:"incomplete,omitempty"`
// the record is retried by the background (an incomplete read, or a failed refresh after an
// operation): scheduling only, its data can be complete
RefreshNeeded bool `bson:"refresh_needed,omitempty"`
// the registry owner at ObservedBlock (lower case; the NameWrapper for a wrapped name, zero
// for a reserved name without a registry owner). "" for records written before it was added
RegistryOwner string `bson:"registry_owner,omitempty"`
// the canonical spelling of the name (the normalizer's output), written with every record:
// the alias check finds records under another spelling by it (see alias.go). indexed
Canon string `bson:"canon,omitempty"`
// contains filtered or unexported fields
}
type NameIndexStats ¶ added in v0.7.0
type NameIndexStats struct {
// "exists" (a unique index on exactly {name: 1}, whatever its name), "created", or
// "missing" (a dry run: it would be created)
NameIndex string
// names with more than one record (only counted when the index is missing): the index can
// not be created until they are resolved by hand
DuplicateNames int
}
NameIndexStats is what VerifyNameIndex found (or did)
type PurgeStats ¶ added in v0.7.0
type PurgeStats struct {
Tombstones int64
// the names whose record is incomplete without an owner: nothing is purged while there are any
Incomplete []string
}
PurgeStats counts what PurgeTombstones did (or would do, in a dry run)
type RefreshStats ¶ added in v0.7.0
type RefreshStats struct {
Total int
Unchanged int
Updated int
// not registered (or lapsed), confirmed at a finalized block: a tombstone
Removed int
// not registered at the latest block, but the finalized block does not confirm it (yet), or
// the cache has a newer registration: left as it is
NotFinal int
// nothing decided (e.g. a contract read failed, the finalized block could not be read), or
// the owner could not be read (the confirmed part is stored, marked): run it again
Failed int
// cached under a spelling that is not the canonical one (e.g. "Foo.any"): the canonical
// name was refreshed, the record under this spelling is left as it is (taken), for an
// operator to look at
NonCanonical int
}
RefreshStats counts what RefreshAll did (or would do, in a dry run)