All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.airlift.airship.coordinator.SimpleDbStateManager Maven / Gradle / Ivy

The newest version!
package io.airlift.airship.coordinator;

import com.amazonaws.AmazonClientException;
import com.amazonaws.services.simpledb.AmazonSimpleDB;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.CreateDomainRequest;
import com.amazonaws.services.simpledb.model.DeleteAttributesRequest;
import com.amazonaws.services.simpledb.model.Item;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.amazonaws.services.simpledb.model.SelectRequest;
import com.amazonaws.services.simpledb.model.SelectResult;
import com.google.common.base.Preconditions;
import io.airlift.airship.shared.Assignment;
import io.airlift.airship.shared.ExpectedSlotStatus;
import io.airlift.airship.shared.SlotLifecycleState;
import io.airlift.log.Logger;
import io.airlift.node.NodeInfo;

import javax.inject.Inject;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.google.common.collect.Lists.newArrayList;

public class SimpleDbStateManager implements StateManager
{
    private static final Logger log = Logger.get(SimpleDbStateManager.class);
    private final AmazonSimpleDB simpleDb;
    private final String domainName;
    private boolean domainCreated;

    @Inject
    public SimpleDbStateManager(AmazonSimpleDB simpleDb, NodeInfo nodeInfo)
    {
        this.simpleDb = simpleDb;
        domainName = "airship-" + nodeInfo.getEnvironment();
    }

    @Override
    public Collection getAllExpectedStates()
    {
        List slots = newArrayList();
        if (isDomainCreated()) {
            try {
                String query = String.format("select itemName, state, binary, config from `%s`", domainName);
                SelectResult select = simpleDb.select(new SelectRequest(query, true));
                for (Item item : select.getItems()) {
                    ExpectedSlotStatus expectedSlotStatus = loadSlotStatus(item);
                    if (expectedSlotStatus != null) {
                        slots.add(expectedSlotStatus);
                    }
                }
                expectedStateStoreUp();
            }
            catch (Exception e) {
                expectedStateStoreDown(e);
            }
        }
        return slots;
    }

    @Override
    public void deleteExpectedState(UUID slotId)
    {
        Preconditions.checkNotNull(slotId, "id is null");

        if (isDomainCreated()) {
            List attributes = newArrayList();
            attributes.add(new Attribute("state", null));
            attributes.add(new Attribute("binary", null));
            attributes.add(new Attribute("config", null));

            try {
                simpleDb.deleteAttributes(new DeleteAttributesRequest().withDomainName(domainName).withItemName(slotId.toString()).withAttributes(attributes));
                expectedStateStoreUp();
            }
            catch (Exception e) {
                expectedStateStoreDown(e);
            }
        }
    }

    @Override
    public void setExpectedState(ExpectedSlotStatus slotStatus)
    {
        Preconditions.checkNotNull(slotStatus, "slotStatus is null");

        if (isDomainCreated()) {
            List attributes = newArrayList();
            attributes.add(new ReplaceableAttribute("state", slotStatus.getStatus().toString(), true));
            if (slotStatus.getAssignment() != null) {
                attributes.add(new ReplaceableAttribute("binary", slotStatus.getAssignment().getBinary(), true));
                attributes.add(new ReplaceableAttribute("config", slotStatus.getAssignment().getConfig(), true));
            }

            try {
                simpleDb.putAttributes(new PutAttributesRequest().withDomainName(domainName).withItemName(slotStatus.getId().toString()).withAttributes(attributes));
                expectedStateStoreUp();
            }
            catch (Exception e) {
                expectedStateStoreDown(e);
            }
        }
    }

    private synchronized boolean isDomainCreated()
    {
        if (!domainCreated) {
            try {
                simpleDb.createDomain(new CreateDomainRequest(domainName));
                domainCreated = true;
            }
            catch (AmazonClientException e) {
                expectedStateStoreDown(e);
            }
        }
        return domainCreated;
    }

    private final AtomicBoolean storeUp = new AtomicBoolean(true);

    private void expectedStateStoreDown(Exception e)
    {
        if (storeUp.compareAndSet(true, false)) {
            log.error(e, "Expected state store is down");
        }
    }

    private void expectedStateStoreUp()
    {
        if (storeUp.compareAndSet(false, true)) {
            log.info("Expected state store is up");
        }
    }

    private ExpectedSlotStatus loadSlotStatus(Item item)
    {
        String id = item.getName();

        String state = null;
        String binary = null;
        String config = null;
        for (Attribute attribute : item.getAttributes()) {
            if ("state".equals(attribute.getName())) {
                state = attribute.getValue();
            }
            else if ("binary".equals(attribute.getName())) {
                binary = attribute.getValue();
            }
            else if ("config".equals(attribute.getName())) {
                config = attribute.getValue();
            }
        }

        // just return null for corrupted entries... these will be marked as unexpected
        // and someone will resolve the conflict (and overwrite the corrupted record)

        if (id == null || state == null) {
            return null;
        }
        try {
            if (binary == null || config == null) {
                return new ExpectedSlotStatus(UUID.fromString(id), SlotLifecycleState.valueOf(state), null);
            }
            else {
                return new ExpectedSlotStatus(UUID.fromString(id), SlotLifecycleState.valueOf(state), new Assignment(binary, config));
            }
        }
        catch (IllegalArgumentException e) {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy