Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelog committed Mar 5, 2013
0 parents commit 21184a7
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
27 changes: 27 additions & 0 deletions Makefile
@@ -0,0 +1,27 @@
CWD=$(shell pwd)
NAME=$(shell basename ${CWD})
CT_LOG=${APP_DIR}/logs
REBAR?=${CWD}/rebar
COOKIE?=cookie_${NAME}
ERL?=/usr/bin/env erl
ERLARGS=-pa ebin -smp enable -name ${NODE} \
-setcookie ${COOKIE} -boot start_sasl

all: clean compile

# Clean all.
clean:
@${REBAR} clean

# Gets dependencies.
getdeps:
@${REBAR} get-deps

# Compiles.
compile:
@${REBAR} compile

# This one runs without a release.
shell: compile
${ERL} ${ERLARGS}

Binary file added rebar
Binary file not shown.
31 changes: 31 additions & 0 deletions rebar.config
@@ -0,0 +1,31 @@
{erl_opts, [
{src_dirs, ["src"]},
warn_unused_vars,
warn_export_all,
warn_shadow_vars,
warn_unused_import,
warn_unused_function,
warn_bif_clash,
warn_unused_record,
warn_deprecated_function,
warn_obsolete_guard,
strict_validation,
warn_export_vars,
warn_exported_vars,
warn_missing_spec,
warn_untyped_record,
debug_info
]}.
{ct_extra_params, "-no_auto_compile -dir ebin"}.
{cover_enabled, true}.
{eunit_opts, [verbose, {skip_deps, true}]}.
{eunit_exclude_deps, true}.
{cover_enabled, true}.
{xref_warnings, true}.
{xref_checks, [
undefined_function_calls,
undefined_functions,
locals_not_used,
deprecated_function_calls,
deprecated_functions
]}.
8 changes: 8 additions & 0 deletions src/simple_cache.app.src
@@ -0,0 +1,8 @@
{application, simple_cache, [
{description, "Small simple cache using ETS"},
{vsn, "git"},
{registered, []},
{applications, [kernel, stdlib]},
{mod, { simple_cache, []}},
{env, []}
]}.
95 changes: 95 additions & 0 deletions src/simple_cache.erl
@@ -0,0 +1,95 @@
%%% @doc Main module for simple_cache.
%%%
%%% Copyright 2013 Marcelo Gornstein <marcelog@@gmail.com>
%%%
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License.
%%% You may obtain a copy of the License at
%%%
%%% http://www.apache.org/licenses/LICENSE-2.0
%%%
%%% Unless required by applicable law or agreed to in writing, software
%%% distributed under the License is distributed on an "AS IS" BASIS,
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%%% See the License for the specific language governing permissions and
%%% limitations under the License.
%%% @end
%%% @copyright Marcelo Gornstein <marcelog@gmail.com>
%%% @author Marcelo Gornstein <marcelog@gmail.com>
%%%
-module(simple_cache).
-author('marcelog@gmail.com').

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Types.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(ETS_TID, atom_to_list(?MODULE)).
-define(NAME(N), list_to_atom(?ETS_TID ++ "_" ++ atom_to_list(N))).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Exports.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Public API.
-export([init/1]).
-export([get/4]).
-export([flush/1, flush/2]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Public API.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% @doc Initializes a cache.
-spec init(string()) -> ok.
init(CacheName) ->
RealName = ?NAME(CacheName),
RealName = ets:new(RealName, [
named_table, {read_concurrency, true}, public, {write_concurrency, true}
]),
ok.

%% @doc Deletes the keys that match the given ets:matchspec() from the cache.
-spec flush(string(), term()) -> true.
flush(CacheName, Key) ->
RealName = ?NAME(CacheName),
ets:delete(RealName, Key).

%% @doc Deletes all keys in the given cache.
-spec flush(string()) -> true.
flush(CacheName) ->
RealName = ?NAME(CacheName),
true = ets:delete_all_objects(RealName).

%% @doc Tries to lookup Key in the cache, and execute the given FunResult
%% on a miss.
-spec get(string(), infinity|pos_integer(), term(), function()) -> term().
get(CacheName, LifeTime, Key, FunResult) ->
RealName = ?NAME(CacheName),
case ets:lookup(RealName, Key) of
[] ->
% Not found, create it.
create_value(RealName, LifeTime, Key, FunResult);
[{Key, R, _CreatedTime, infinity}] -> R; % Found, wont expire, return the value.
[{Key, R, CreatedTime, LifeTime}] ->
TimeElapsed = now_usecs() - CreatedTime,
if
TimeElapsed > (LifeTime * 1000) ->
% expired? create a new value
create_value(RealName, LifeTime, Key, FunResult);
true -> R % Not expired, return it.
end
end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Private API.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% @doc Creates a cache entry.
-spec create_value(string(), pos_integer(), term(), function()) -> term().
create_value(RealName, LifeTime, Key, FunResult) ->
R = FunResult(),
ets:insert(RealName, {Key, R, now_usecs(), LifeTime}),
R.

%% @doc Returns total amount of microseconds since 1/1/1.
-spec now_usecs() -> pos_integer().
now_usecs() ->
{MegaSecs, Secs, MicroSecs} = os:timestamp(),
MegaSecs * 1000000000000 + Secs * 1000000 + MicroSecs.

0 comments on commit 21184a7

Please sign in to comment.