NAME

Geo::Coder::Free::MissCache - process-level memory of lookups that found nothing

VERSION

Version 0.48

SYNOPSIS

use Geo::Coder::Free::MissCache;

my $scope  = Geo::Coder::Free::MissCache->scope_for('OpenAddresses', '/data/openaddresses');
my $digest = 'AB12CD34';

# A lookup found nothing: remember that, so the next caller does not
# have to read the same database to learn it again.
Geo::Coder::Free::MissCache->remember($scope, $digest);

# A caller about to do the work asks first.
if(Geo::Coder::Free::MissCache->missed($scope, $digest)) {
    print "already looked for $digest\n";
}

# The data behind the cache was rebuilt, so forget everything.
Geo::Coder::Free->clear_miss_cache();

DESCRIPTION

Every backend in Geo::Coder::Free has the same problem: an address that is not in its data is not found on every call, and each call pays for the whole search again. Geo::Coder::Free::MissCache is the one place where the backends record those misses, so the process remembers the absence once and every later call - through any instance of any backend - answers without touching a database.

Entries are held in memory, in the process, and are not shared between processes. They expire after an hour by default. That is long enough to spare a batch, a web request or a test run the repeated work, and short enough that a process which stays up after its data is rebuilt does not keep answering from a stale memory forever; Geo::Coder::Free-clear_miss_cache()> empties the cache at once for that case. Expired entries are discarded when they are next asked about, and a sweep runs at most once a minute as new misses are recorded, so the cache does not grow without bound.

A miss is only ever remembered, never inferred: nothing here decides that an answer will be missing, it only stores that a backend has already found that it is.

METHODS

scope_for

my $scope = Geo::Coder::Free::MissCache->scope_for('OpenAddresses', $dir);

Builds the name a backend stores its misses under. The parts are joined with a zero byte, so the first part names the backend and the rest say which data set is being read - two OpenAddresses directories hold different data, and a miss in one says nothing about the other. clear() uses the same convention: giving it a backend name clears every data set that backend opened.

missed

my $seen = Geo::Coder::Free::MissCache->missed($scope, $key);

True if $key was remembered as a miss in $scope and has not expired. An expired entry is deleted as it is found. A missing entry is false and is not an error.

remember

Geo::Coder::Free::MissCache->remember($scope, $key);

Records that $key found nothing in $scope, for as long as "expires_after" says. Recording the same miss again refreshes it.

forget

Geo::Coder::Free::MissCache->forget($scope, $key);

Forgets one miss, leaving the rest of $scope alone. Returns true if there was an entry to forget. A backend calls this when a lookup that had been remembered as a miss now succeeds, so a hit is never skipped on the strength of an older miss.

clear

Geo::Coder::Free::MissCache->clear();
Geo::Coder::Free::MissCache->clear('OpenAddresses');

With no argument, forgets every miss in every scope. With a scope, forgets the misses in that scope and in every scope below it: clear('OpenAddresses') empties every OpenAddresses data set this process has opened. Returns true.

size

my $count = Geo::Coder::Free::MissCache->size();
my $count = Geo::Coder::Free::MissCache->size('Local');

How many misses are currently remembered, in all scopes or in one scope. Expired entries are discarded first, so this is the number of live entries.

expires_after

my $seconds = Geo::Coder::Free::MissCache->expires_after();
Geo::Coder::Free::MissCache->expires_after(600);

How long a remembered miss lasts, in seconds. Without an argument it answers with the current setting, which is one hour. Setting it to 0 makes every miss expire as soon as it is recorded, which turns the cache off. It is a setting of the process, not of an object, like the cache itself.