Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor OriginsInventory. #62

Merged

Conversation

mikkokar
Copy link
Contributor

  • Use QueueDrainingEventProcessor to ensure lockless consistency in face of concurrent updates.
  • Improve origin state management for added/modified/removed monitored origins.

- Use event queue to ensure concurrent updates are handled correctly.
- Improve ability to detect added/modified/removed origins.
enum Outcome {
RELOADED,
UNCHANGED
}

/**
* Result or registry reload.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result of registry reload?

@@ -17,6 +17,8 @@

/**
* Informed about state changes.
*
* @param <S> State type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention would use this style: * @param <S> state type rather than full sentences for @param, @return @throws etc.

import static org.slf4j.LoggerFactory.getLogger;

/**
* An inventory of the origins configured for a single application.
*/
@ThreadSafe
public final class OriginsInventory
implements OriginHealthStatusMonitor.Listener, OriginsCommandsListener, ActiveOrigins, OriginsInventoryStateChangeListener.Announcer, Closeable {
implements OriginHealthStatusMonitor.Listener,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number of interfaces here may indicate that this class is taking on too many responsibilities, but we can look into that later.

private final AtomicBoolean closed = new AtomicBoolean(false);

private Map<Id, MonitoredOrigin> origins = ImmutableMap.of();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use Collections.emptyMap as that does not require an external dependency.

@Override
public void submit(Object event) {
if (event instanceof SetOriginsEvent) {
addOriginsEventHandler((SetOriginsEvent) event);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add or set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to setOriginsEventHandler.

}

public void addOriginsEventHandler(SetOriginsEvent event) {
Set<Origin> newOrigins = event.newOrigins;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested refactoring to encapsulate concept of origin changes:

    Map<Id, Origin> newOriginsMap = event.newOrigins.stream()
                .collect(toMap(Origin::id, o -> o));

        OriginChanges originChanges = new OriginChanges();

        concat(this.origins.keySet().stream(), newOriginsMap.keySet().stream()).collect(toSet()).forEach(
                originId -> {
                    Origin origin = newOriginsMap.get(originId);

                    if (isNewOrigin(originId, origin)) {
                        MonitoredOrigin monitoredOrigin = addMonitoredEndpoint(origin);
                        originChanges.addOrReplaceOrigin(originId, monitoredOrigin);

                    } else if (isUpdatedOrigin(originId, origin)) {
                        MonitoredOrigin monitoredOrigin = changeMonitoredEndpoint(origin);
                        originChanges.addOrReplaceOrigin(originId, monitoredOrigin);

                    } else if (isUnchangedOrigin(originId, origin)) {
                        LOG.info("Existing origin has been left unchanged. Origin={}:{}", appId, origin);
                        originChanges.keepExistingOrigin(originId, this.origins.get(originId));

                    } else if (isRemovedOrigin(originId, origin)) {
                        removeMonitoredEndpoint(originId);
                        originChanges.noteRemovedOrigin();
                    }
                }
        );

        this.origins = originChanges.updatedOrigins();

        if (originChanges.changed()) {
            notifyStateChange();
        }
    }

    private class OriginChanges {
        ImmutableMap.Builder<Id, MonitoredOrigin> monitoredOrigins = ImmutableMap.builder();
        AtomicBoolean changed = new AtomicBoolean(false);

        void addOrReplaceOrigin(Id originId, MonitoredOrigin origin) {
            monitoredOrigins.put(originId, origin);
            changed.set(true);
        }

        void keepExistingOrigin(Id originId, MonitoredOrigin origin) {
            monitoredOrigins.put(originId, origin);
        }

        void noteRemovedOrigin() {
            changed.set(true);
        }

        boolean changed() {
            return changed.get();
        }

        Map<Id, MonitoredOrigin> updatedOrigins() {
            return monitoredOrigins.build();
        }
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@Test
public void addingANewOriginWillAddToActiveSetAndInitiateTheMonitoring() {
inventory.addOrigins(ORIGIN);
public void setNewOrigins() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this test trying to prove? Its name doesn't explain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

@Test
public void updatesOriginPortNumber() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is also not as informative as it could be. Perhaps something like "replaces origin when port number has changed"?

Copy link
Contributor Author

@mikkokar mikkokar Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is a longwinded way of saying "(origins inventory) updates origin port number" ;-)

}

@Test
public void updatesOriginHostName() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is also not as informative as it could be. Perhaps something like "replaces origin when host name has changed"?

Copy link
Contributor Author

@mikkokar mikkokar Jan 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... again which is just a longer way saying "(origins inventory) updates origin host name".

}

@Test
public void stopsMonitoringModifiedOrigins() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stops and restarts?

@mikkokar mikkokar merged commit df1dc8d into ExpediaGroup:spi-refactor Jan 12, 2018
alobodzki pushed a commit that referenced this pull request Jan 12, 2018
* Refactor OriginsInventory.
- Use event queue to ensure concurrent updates are handled correctly.
- Improve ability to detect added/modified/removed origins.
alobodzki added a commit that referenced this pull request Jan 22, 2018
@mikkokar mikkokar deleted the spi-refactor-origins-inventory branch June 27, 2018 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants