Skip to content

Commit

Permalink
Fixed cycle-break algorithm + version 0.2.1 (#7)
Browse files Browse the repository at this point in the history
* Fixed the cycle-break algorithm, which was not breaking cycles in some real-life corner cases. Sorry for not adding new tests: the fixed issues occur depending on the order of the cost allocation visit, which is not predictable when writing tests.

* Version 0.2.1
  • Loading branch information
marc-perreaut authored Aug 5, 2022
1 parent 3c14d7b commit ad04f08
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 37 deletions.
80 changes: 44 additions & 36 deletions cloud_cost_allocation/cost_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,44 +682,52 @@ def visit_for_cycles(self,
cycle_message.write(visited_service_instance.get_self_id() + ",")
cycle_message.write(self.get_self_id())

# Search for the first and the second service instances
first_service_instance = None
second_service_instance = None
for service in service_precedence_list:
for service_instance in visited_service_instance_list:
if service_instance.service == service:
if not first_service_instance:
first_service_instance = service_instance
break
elif not second_service_instance:
second_service_instance = service_instance
break
if second_service_instance:
# Iterate in reducing service precedence list
working_service_precedence_list = service_precedence_list.copy()
while working_service_precedence_list:

# Search for the first service and the second service
first_service = None
second_service = None
for service in working_service_precedence_list:
for service_instance in visited_service_instance_list:
if service_instance.service == service:
if not first_service:
first_service = service
break
elif not second_service:
second_service = service
break
if second_service:
break

# If two services in the precedence list do not exist in the cycle, the cycle cannot be broken
if not second_service:
break

# If two services in the precedence list do not exist in the cycle, the cycle cannot be broken
if not second_service_instance:
error("Unbreakable cost allocation cycle detected: " + cycle_message.getvalue())
raise UnbreakableCycleException

# Break the cycle before the first service instance
for cost_item in first_service_instance.cost_items:
provider_service_instance = cost_item.get_consumer_cost_item_provider_service_instance()
if provider_service_instance and\
not provider_service_instance.is_visited and provider_service_instance.is_being_visited:
cost_item.is_removed_from_cycle = True
info("Broke cost allocation cycle at provider service instance " +
provider_service_instance.get_self_id() + ", as service instances " +
first_service_instance.get_self_id() + " and " + second_service_instance.get_self_id() +
" have been identified in the precedence list and in the cycle " + cycle_message.getvalue())

# Iterate to the next cycle break
raise BreakableCycleException

# This code should be unreachable, but just in case
error("Unbreakable cost allocation cycle detected, although service instances in the precedence list " +
first_service_instance.get_self_id() + " and " + second_service_instance.get_self_id() +
" have been identified in the cycle:" + cycle_message.getvalue())
# Try to break the cycle before the first service
for service_instance in visited_service_instance_list:
if service_instance.service == first_service:
for cost_item in service_instance.cost_items:
provider_service_instance = cost_item.get_consumer_cost_item_provider_service_instance()
if provider_service_instance and\
not provider_service_instance.is_visited and provider_service_instance.is_being_visited:
cost_item.is_removed_from_cycle = True
info("Broke cost allocation cycle at provider service instance " +
provider_service_instance.get_self_id() + " of service instance " +
service_instance.get_self_id() + ", as services " +
first_service + " and " + second_service +
" have been identified in the precedence list and in the cycle " +
cycle_message.getvalue())

# Iterate to the next cycle break
raise BreakableCycleException

# Reduce service precedence list
working_service_precedence_list.pop(0)

# If this code is reached, it means cycle could not be broken
error("Unbreakable cost allocation cycle detected: " + cycle_message.getvalue())
raise UnbreakableCycleException

# Set being visited
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Setup
setup(
name='cloud-cost-allocation',
version='0.2.0',
version='0.2.1',
description='Python library for shared, hierarchical cost allocation based on user-defined metrics.',
long_description=readme,
long_description_content_type='text/markdown',
Expand Down

0 comments on commit ad04f08

Please sign in to comment.