Keep references purely in erlang

Refernces contain three pieces of data which we already keep in the
erlang record. Keep the repository it belongs to in the record as well
and remove resource in the NIF. This makes the code easier to reason
about, as we don't need to keep any reference counts or GC the C
struct.

This does mean we cannot re-use references across geef_repo restarts,
but that's probably a good thing.
This commit is contained in:
Carlos Martín Nieto
2013-08-31 17:23:46 +02:00
parent da7a070522
commit 70867b9615
6 changed files with 185 additions and 199 deletions

View File

@@ -49,28 +49,20 @@ reference_to_id(_Repo, _Refname) ->
reference_glob(_Repo, _Glob) ->
nif_error(?LINE).
reference_lookup(_Repo, _Refname) ->
-spec reference_lookup(term(), binary() | iolist()) -> {ok, geef_ref:ref_type(), geef_oid:oid()} | {error, term()}.
reference_lookup(_RepoHandle, _Refname) ->
nif_error(?LINE).
-spec reference_iterator(term(), iolist() | undefined) -> {ok, geef_ref:iterator()} | {error, term()}.
reference_iterator(_Repo, _Regexp) ->
nif_error(?LINE).
-spec reference_next(geef_ref:iterator()) -> {ok, term()} | {error, iterover | term()}.
-spec reference_next(geef_ref:iterator()) -> {ok, binary(), geef_ref:ref_type(), geef_oid:oid() | binary()} | {error, iterover | term()}.
reference_next(_Handle) ->
nif_error(?LINE).
reference_target(_Handle) ->
nif_error(?LINE).
reference_resolve(_Handle) ->
nif_error(?LINE).
reference_type(_Handle) ->
nif_error(?LINE).
-spec reference_name(term()) -> {ok, binary()} | {error, term()}.
reference_name(_Handle) ->
-spec reference_resolve(term(), binary()) -> {ok, geef_oid:oid()} | {error, term()}.
reference_resolve(_RepoHandle, _Name) ->
nif_error(?LINE).
reference_dwim(_Handle, _Name) ->

View File

@@ -1,4 +1,4 @@
-record(geef_reference, {handle, name :: binary(), type :: oid | symbolic, target :: binary() | geef_oid:oid()}).
-record(geef_reference, {repo :: pid(), name :: binary(), type :: geef_ref:type(), target :: geef_ref:target()}).
-record(geef_oid, {oid :: binary()}).
-record(geef_object, {type :: atom(), id :: geef_oid:oid(), handle}).
-record(geef_index_entry,

View File

@@ -5,41 +5,46 @@
-include("geef_records.hrl").
-type iterator() :: #geef_iterator{type :: ref}.
-type type() :: oid | symbolic.
-type target() :: binary | geef_oid:oid().
-type ref() :: #geef_reference{name :: binary()}.
-export_type([reference/0, iterator/0]).
-spec new(term()) -> ref().
new(Handle) ->
{ok, Name} = geef_nif:reference_name(Handle),
new(Name, Handle).
-spec new(binary(), term()) -> ref().
new(Name, Handle) ->
Type = geef_nif:reference_type(Handle),
Bin = geef_nif:reference_target(Handle),
Target = case Type of
symbolic ->
Bin;
oid ->
#geef_oid{oid=Bin}
end,
#geef_reference{handle=Handle, name=Name, type=Type, target=Target}.
-spec create(pid(), iolist(), geef_oid:oid() | binary(), boolean()) -> {ok, ref()} | {error, term()}.
-spec create(pid(), iolist(), target(), boolean()) -> {ok, ref()} | {error, term()}.
create(Repo, Refname, Target, Force) ->
case geef_repo:create_reference(Repo, Refname, Target, Force) of
{ok, Ref} ->
{ok, new(Refname, Ref)};
RepoHandle = geef_repo:handle(Repo),
case do_create(RepoHandle, Refname, Target, Force) of
ok ->
{ok, make(Repo, Refname, Target)};
Err = {error, _} ->
Err
end.
-spec do_create(term(), binary(), target(), boolean()) -> ok | {error, term}.
do_create(RepoHandle, Refname, #geef_oid{oid=Oid}, Force) ->
geef_nif:reference_create(RepoHandle, Refname, oid, Oid, Force);
do_create(RepoHandle, Refname, Target, Force) ->
geef_nif:reference_create(RepoHandle, Refname, symbolic, Target, Force).
-spec make(pid(), binary(), target()) -> ref().
make(Repo, Name, Target = #geef_oid{}) ->
#geef_reference{repo=Repo, name=Name, type=oid, target=Target};
make(Repo, Name, Target) ->
#geef_reference{repo=Repo, name=Name, type=symbolic, target=Target}.
-spec make(pid(), binary(), type(), binary()) -> ref().
make(Repo, Name, oid, Target) ->
#geef_reference{repo=Repo, name=Name, type=oid, target=#geef_oid{oid=Target}};
make(Repo, Name, symbolic, Target) ->
#geef_reference{repo=Repo, name=Name, type=symbolic, target=Target}.
-spec lookup(pid(), iolist()) -> {ok, ref()} | {error, term()}.
lookup(Repo, Refname) ->
Name = iolist_to_binary(Refname),
case geef_repo:lookup_reference(Repo, Name) of
{ok, Ref} ->
{ok, new(Name, Ref)};
RepoHandle = geef_repo:handle(Repo),
case geef_nif:reference_lookup(RepoHandle, Name) of
{ok, Type, Target} ->
{ok, make(Repo, Name, Type, Target)};
Other ->
Other
end.
@@ -58,10 +63,10 @@ iterator(Repo) ->
iterator(Repo, undefined).
-spec next(iterator()) -> {ok, ref()} | {error, term()}.
next(#geef_iterator{type=ref, handle=Handle}) ->
next(#geef_iterator{type=ref, repo=Repo, handle=Handle}) ->
case geef_nif:reference_next(Handle) of
{ok, RefHandle} ->
{ok, new(RefHandle)};
{ok, Name, Type, Target} ->
{ok, make(Repo, Name, Type, Target)};
Other ->
Other
end.
@@ -69,20 +74,22 @@ next(#geef_iterator{type=ref, handle=Handle}) ->
-spec resolve(ref()) -> {ok, ref()} | {error, term()}.
resolve(Ref = #geef_reference{type=oid}) ->
{ok, Ref}; % resolving an oid ref is a no-op, skip going into the NIF
resolve(#geef_reference{type=symbolic, handle=Handle}) ->
case geef_nif:reference_resolve(Handle) of
{ok, Ref} ->
{ok, new(Ref)};
resolve(#geef_reference{repo=Repo, name=Name, type=symbolic}) ->
RepoHandle = geef_repo:handle(Repo),
case geef_nif:reference_resolve(RepoHandle, Name) of
{ok, Type, Target} ->
{ok, make(Repo, Name, Type, Target)};
Other = {error, _} ->
Other
end.
-spec dwim(pid(), iolist()) -> {ok, ref()} | {error, term()}.
dwim(Repo, Name) ->
case geef_repo:reference_dwim(Repo, Name) of
{ok, Handle} ->
{ok, new(Handle)};
Err ->
RepoHandle = geef_repo:handle(Repo),
case geef_nif:reference_dwim(RepoHandle, Name) of
{ok, RealName, Type, Target} ->
{ok, make(Repo, RealName, Type, Target)};
Err = {error, _}->
Err
end.