Description
Currently, the fact that the DbNode
and DbLink
table are single tables makes it hard to implement the link uniqueness constraints on the database level. As a result we currently have the aiida.orm.utils.links.validate_link
function, that performs these checks. However, ideally this is done on the database level.
To implement this, one needs to split the DbNode
table into three separate tables:
DbWorfklowNode
DbCalculationNode
DbDataNode
The DbLink
table can then be split into six tables, one for each link type:
DbCreate
DbReturn
DbCallCalc
DbCallWork
DbInputCalc
DbInputWork
Each of these link tables will have three columns source
, target
, label
, denoting the source node, target node and the link label. The uniqueness constraints would then be as follows:
DbCreate
Unique('target')
Unique('source', 'label')
DbReturn
Unique('source', 'label')
DbCallCalc
Unique('target')
Unique('source', 'label')
(optional)
DbCallWork
Unique('target')
Unique('source', 'label')
(optional)
DbInputCalc
Unique('target', 'label')
DbInputWork
Unique('target', 'label')
This would also allow to reinsert the following piece of code that was removed from Node._add_dblink_from
in commit that automatically generated links in a thread safe way, based on database constraints:
if label is None:
autolabel_idx = 1
existing_from_autolabels = list(DbLink.objects.filter(
output=self._dbnode,
label__startswith="link_").values_list('label', flat=True))
while "link_{}".format(autolabel_idx) in existing_from_autolabels:
autolabel_idx += 1
safety_counter = 0
while True:
safety_counter += 1
if safety_counter > 100:
# Well, if you have more than 100 concurrent addings
# to the same node, you are clearly doing something wrong...
raise InternalError("Hey! We found more than 100 concurrent"
" adds of links "
"to the same nodes! Are you really doing that??")
try:
self._do_create_link(src, "link_{}".format(autolabel_idx), link_type)
break
except UniquenessError:
# Retry loop until you find a new loop
autolabel_idx += 1