Documentation says that
make_ref() -> ref()
Returns an almost unique reference.
The returned reference will re-occur after approximately 282 calls;
therefore it is unique enough for practical purposes.
But my eyes tell me that between VM restarts I could easily get the same ref:
[~] erl
Erlang R14B04 (erts-5.8.5)
1> make_ref().
#Ref<0.0.0.33>
2> make_ref().
#Ref<0.0.0.37>
^C
[~] erl
Erlang R14B04 (erts-5.8.5)
1> make_ref().
#Ref<0.0.0.33>
So, how unique Erlang’s Refs are? Are they suitable to be used as an unique “tag” generator when tags are persistent in mq or db and may be generated by different VM sessions.
I know UUIDs could be used for this. It’s also well known that pids() are repeatable, reusable and by no means unique if serialized and then loaded from persistent storage.
Question is, what are refs() — more like UUIDs or more like pids()? Are refs() unique between nodes? Between restarts? Is there any official info on this topic?
References, which are related to the name of a node, do not imply randomness, just uniqueness.
As you've already noticed, they're created in a cyclic way.
Also, you're correct on the fact references are unique only for the life span of a node. Once, you restart the VM, references can be repeated.
As in the case of PIDs, printed references #Ref<W.X.Y.Z>
contain - as their first element (W
) - information about the node number:
erl -sname right
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9 (abort with ^G)
(right@mars)1> register(right, self()).
true
(right@mars)2> receive M -> M end.
#Ref<6793.0.0.41>
(right@mars)3>
erl -sname left
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V5.9 (abort with ^G)
(left@mars)1> {right, 'right@mars'} ! make_ref().
#Ref<0.0.0.41>
(left@mars)2>
Notice how in this case the W
for the reference is 0
in the local node, 6793
in the remote one.
In any distributed system, to be able to generate a unique identifier, you have to either rely on a central atomic ID generator with persistent storage, or ensure proper configuration of the cluster at any point in time. An example of the second case follows.
In a distributed Erlang cluster {node(), now()}
can be considered unique. If you can make sure that your clock is reasonably configured and you won't start two nodes with the same name, you could try using {node(), now(), make_ref()}
, which would make possibility of collision negligible.