Skip to content

Commit

Permalink
refactor: alias store mountpoints handling
Browse files Browse the repository at this point in the history
  • Loading branch information
makkus committed Feb 3, 2024
1 parent 3ddb2cc commit f707c00
Showing 1 changed file with 132 additions and 49 deletions.
181 changes: 132 additions & 49 deletions src/kiara/registries/aliases/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def __init__(self, kiara: "Kiara"):
self._cached_aliases: Union[Dict[str, AliasItem], None] = None
self._cached_aliases_by_id: Union[Dict[uuid.UUID, Set[AliasItem]], None] = None

self._cached_dynamic_aliases: Union[Dict[str, AliasItem], None] = None

def register_archive(
self,
archive: AliasArchive,
Expand Down Expand Up @@ -165,6 +167,7 @@ def register_archive(
self._cached_aliases = None
self._cached_aliases_by_id = None
self._dynamic_stores = None
self._cached_dynamic_aliases = None


event = AliasArchiveAddedEvent(
Expand All @@ -191,14 +194,14 @@ def alias_archives(self) -> Mapping[str, AliasArchive]:
return self._alias_archives

def get_archive(
self, archive_id: Union[str, None] = None
self, archive_alias: Union[str, None] = None
) -> Union[AliasArchive, None]:
if archive_id is None:
archive_id = self.default_alias_store
if archive_id is None:
if archive_alias is None:
archive_alias = self.default_alias_store
if archive_alias is None:
raise Exception("Can't retrieve default alias archive, none set (yet).")

archive = self._alias_archives.get(archive_id, None)
archive = self._alias_archives.get(archive_alias, None)
return archive

@property
Expand All @@ -213,7 +216,13 @@ def aliases_by_id(self) -> Mapping[uuid.UUID, Set[AliasItem]]:
return self._cached_aliases_by_id # type: ignore

@property
def aliases(self) -> Dict[str, AliasItem]:
def dynamic_aliases(self) -> Dict[str, AliasItem]:
if self._cached_dynamic_aliases is None:
self.aliases
return self._cached_dynamic_aliases

@property
def aliases(self) -> Mapping[str, AliasItem]:
"""Retrieve a map of all available aliases, context wide, with the registered archive aliases as values."""
if self._cached_aliases is not None:
return self._cached_aliases
Expand Down Expand Up @@ -254,39 +263,59 @@ def aliases(self) -> Dict[str, AliasItem]:

return self._cached_aliases

@property
def dynamic_stores(self) -> List[str]:
if self._dynamic_stores is None:
self.aliases
return self._dynamic_stores

def find_value_id_for_alias(self, alias: str) -> Union[uuid.UUID, None]:
"""Find the value id for a given alias.
This method will check all registered archives if they have the alias registered (under their respective mountpoints, if applicable), then it will check the archives that have dynamic aliases (i.e. they don't
return a list of all available aliases, but 'None' if queried).
Once found, the value will be stored in a cache for faster retrieval next time.
"""

alias_item = self.aliases.get(alias, None)
if alias_item is not None:
return alias_item.value_id

if "#" in alias:
alias_item = self.dynamic_aliases.get(alias, None)
if alias_item is not None:
return alias_item.value_id

if "#" not in alias:
archive_alias = self.default_alias_store
rest = alias
else:
mountpoint, rest = alias.split("#", maxsplit=1)
archive = self._mountpoints.get(mountpoint, None)
if archive is None:
archive_alias = self._mountpoints.get(mountpoint, None)

if archive_alias is None:
return None
archive = self.get_archive(archive_id=archive)
archive.
return None

mountpoint, rest = alias.split(".", maxsplit=1)
if mountpoint not in self._mountpoints.keys():
if archive_alias not in self.dynamic_stores:
return None
archive_id = self._mountpoints[mountpoint]
archive = self.get_archive(archive_id=archive_id)

if archive is None:
# means no registered prefix
archive = self.get_archive()
assert archive is not None
v_id = archive.find_value_id_for_alias(alias)
else:
v_id = archive.find_value_id_for_alias(alias=rest)

# TODO: cache this?
return v_id
archive = self.get_archive(archive_alias=archive_alias)
result_value_id = archive.find_value_id_for_alias(alias=rest)
if result_value_id:
alias_item = AliasItem(
full_alias=alias,
rel_alias=rest,
value_id=result_value_id,
alias_archive=archive_alias,
alias_archive_id=archive.archive_id,
)
self.dynamic_aliases[alias] = alias_item
return result_value_id
else:
return None

def _get_value_id(self, value_id: Union[uuid.UUID, ValueLink, str]) -> uuid.UUID:
"""Convenience method to ensure a uuid.UUID type for a value id."""

if not isinstance(value_id, uuid.UUID):
# fallbacks for common mistakes, this should error out if not a Value or string.
Expand All @@ -310,6 +339,10 @@ def find_aliases_for_value_id(
value_id: Union[uuid.UUID, ValueLink, str],
search_dynamic_archives: bool = False,
) -> Set[str]:
"""Finds all registered aliases for the provided value id.
If 'search_dynamic_archives' is set to 'True', this method will also search all dynamic archives for the value id, which is not being done by default for performance reasons.
"""

value_id = self._get_value_id(value_id=value_id)

Expand All @@ -318,10 +351,18 @@ def find_aliases_for_value_id(
if search_dynamic_archives:
for archive_alias, archive in self._alias_archives.items():
_aliases = archive.find_aliases_for_value_id(value_id=value_id)
# TODO: cache those results
if _aliases:
for a in _aliases:
aliases.add(f"{archive_alias}.{a}")
full_alias = f"{archive_alias}#{a}"
alias_item = AliasItem(
full_alias=full_alias,
rel_alias=a,
value_id=value_id,
alias_archive=archive_alias,
alias_archive_id=archive.archive_id,
)
self.dynamic_aliases[full_alias] = alias_item
aliases.add(full_alias)

return aliases

Expand All @@ -333,21 +374,45 @@ def register_aliases(
alias_store: Union[str, None] = None,
):

aliases_to_store = {}
for alias in aliases:
if alias in INVALID_ALIAS_NAMES:
if "#" in alias:
mountpoint, alias_name = alias.split("#", maxsplit=1)
alias_store_alias = self._mountpoints.get(mountpoint, None)
if alias_store_alias is None:
raise Exception(f"Invalid mountpoint: '{mountpoint}' not registered.")

if alias_store and alias_store != alias_store_alias:
raise Exception(
f"Can't register alias '{alias}': conflicting alias store references '{alias_store}' != '{alias_store_alias}'."
)

if alias_store:
alias_store_alias = alias_store

else:
alias_store_alias = self.default_alias_store
alias_name = alias

if alias_name in INVALID_ALIAS_NAMES:
raise KiaraException(
msg=f"Invalid alias name: {alias}.",
details=f"The following names can't be used as alias: {', '.join(INVALID_ALIAS_NAMES)}.",
)
if alias in self._mountpoints.keys():

if "#" in alias_name:
raise KiaraException(
msg=f"Invalid alias name: {alias}.",
details="Alias is used as mountpoint in this context.",
details="Alias can't contain a '#' character.",
)
if ":" in alias_name:
raise KiaraException(
msg=f"Invalid alias name: {alias}.",
details="Alias can't contain a ':' character.",
)

value_id = self._get_value_id(value_id=value_id)
store_name = self.default_alias_store
store: AliasStore = self.get_archive(archive_id=store_name) # type: ignore
aliases_to_store.setdefault(alias_store_alias, []).append(alias_name)

self.aliases # noqu

if not allow_overwrite:
Expand All @@ -357,25 +422,43 @@ def register_aliases(
duplicates.append(alias)

if duplicates:
raise Exception(f"Duplicate aliases: {duplicates}")
raise Exception(f"Aliases already registered: {duplicates}")

store.register_aliases(value_id, *aliases)
value_id = self._get_value_id(value_id=value_id)

for alias in aliases:
alias_item = AliasItem(
full_alias=alias,
rel_alias=alias,
value_id=value_id,
alias_archive=store_name,
alias_archive_id=store.archive_id,
)
for store_alias, aliases_for_store in aliases_to_store.items():

store: AliasStore = self.get_archive(archive_alias=store_alias) # type: ignore
if store is None:
raise Exception(f"Invalid alias store: '{store_alias}' not registered.")
if not store.is_writeable():
raise Exception(f"Can't register aliases in store '{store_alias}': store is read-only.")

for store_alias, aliases_for_store in aliases_to_store.items():

store = self.get_archive(archive_alias=store_alias) # type: ignore
store.register_aliases(value_id, *aliases_for_store)

for alias in aliases:
alias_item = AliasItem(
full_alias=alias,
rel_alias=alias,
value_id=value_id,
alias_archive=store_alias,
alias_archive_id=store.archive_id,
)

if store_alias == self.default_alias_store:
actual_alias = alias
else:
actual_alias = f"{store_alias}#{alias}"

if alias in self.aliases.keys():
logger.info("alias.replace", alias=alias)
# raise NotImplementedError()
if actual_alias in self.aliases.keys():
logger.info("alias.replace", alias=actual_alias)
# raise NotImplementedError()

self.aliases[alias] = alias_item
self._cached_aliases_by_id.setdefault(value_id, set()).add(alias_item) # type: ignore
self.aliases[actual_alias] = alias_item
self._cached_aliases_by_id.setdefault(value_id, set()).add(alias_item)


#
Expand Down

0 comments on commit f707c00

Please sign in to comment.