org.apache.aurora.scheduler.storage.log.WriteAheadStorage.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.aurora.scheduler.storage.log.WriteAheadStorage.java

Source

/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.aurora.scheduler.storage.log;

import java.util.Set;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;

import org.apache.aurora.gen.storage.Op;
import org.apache.aurora.gen.storage.PruneJobUpdateHistory;
import org.apache.aurora.gen.storage.RemoveJob;
import org.apache.aurora.gen.storage.RemoveLock;
import org.apache.aurora.gen.storage.RemoveQuota;
import org.apache.aurora.gen.storage.RemoveTasks;
import org.apache.aurora.gen.storage.RewriteTask;
import org.apache.aurora.gen.storage.SaveCronJob;
import org.apache.aurora.gen.storage.SaveFrameworkId;
import org.apache.aurora.gen.storage.SaveHostAttributes;
import org.apache.aurora.gen.storage.SaveJobInstanceUpdateEvent;
import org.apache.aurora.gen.storage.SaveJobUpdate;
import org.apache.aurora.gen.storage.SaveJobUpdateEvent;
import org.apache.aurora.gen.storage.SaveLock;
import org.apache.aurora.gen.storage.SaveQuota;
import org.apache.aurora.gen.storage.SaveTasks;
import org.apache.aurora.scheduler.events.EventSink;
import org.apache.aurora.scheduler.events.PubsubEvent;
import org.apache.aurora.scheduler.storage.AttributeStore;
import org.apache.aurora.scheduler.storage.CronJobStore;
import org.apache.aurora.scheduler.storage.JobUpdateStore;
import org.apache.aurora.scheduler.storage.LockStore;
import org.apache.aurora.scheduler.storage.QuotaStore;
import org.apache.aurora.scheduler.storage.SchedulerStore;
import org.apache.aurora.scheduler.storage.Storage.MutableStoreProvider;
import org.apache.aurora.scheduler.storage.TaskStore;
import org.apache.aurora.scheduler.storage.entities.IHostAttributes;
import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
import org.apache.aurora.scheduler.storage.entities.IJobInstanceUpdateEvent;
import org.apache.aurora.scheduler.storage.entities.IJobKey;
import org.apache.aurora.scheduler.storage.entities.IJobUpdate;
import org.apache.aurora.scheduler.storage.entities.IJobUpdateEvent;
import org.apache.aurora.scheduler.storage.entities.IJobUpdateKey;
import org.apache.aurora.scheduler.storage.entities.ILock;
import org.apache.aurora.scheduler.storage.entities.ILockKey;
import org.apache.aurora.scheduler.storage.entities.IResourceAggregate;
import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
import org.slf4j.Logger;

import uno.perk.forward.Forward;

import static java.util.Objects.requireNonNull;

import static org.apache.aurora.scheduler.storage.log.LogStorage.TransactionManager;

/**
 * Mutable stores implementation that translates all operations to {@link Op}s (which are passed
 * to a provided {@link TransactionManager}) before forwarding the operations to delegate mutable
 * stores.
 */
@Forward({ SchedulerStore.class, CronJobStore.class, TaskStore.class, LockStore.class, QuotaStore.class,
        AttributeStore.class, JobUpdateStore.class })
class WriteAheadStorage extends WriteAheadStorageForwarder
        implements MutableStoreProvider, SchedulerStore.Mutable, CronJobStore.Mutable, TaskStore.Mutable,
        LockStore.Mutable, QuotaStore.Mutable, AttributeStore.Mutable, JobUpdateStore.Mutable {

    private final TransactionManager transactionManager;
    private final SchedulerStore.Mutable schedulerStore;
    private final CronJobStore.Mutable jobStore;
    private final TaskStore.Mutable taskStore;
    private final LockStore.Mutable lockStore;
    private final QuotaStore.Mutable quotaStore;
    private final AttributeStore.Mutable attributeStore;
    private final JobUpdateStore.Mutable jobUpdateStore;
    private final Logger log;
    private final EventSink eventSink;

    /**
     * Creates a new write-ahead storage that delegates to the providing default stores.
     *
     * @param transactionManager External controller for transaction operations.
     * @param schedulerStore Delegate.
     * @param jobStore       Delegate.
     * @param taskStore      Delegate.
     * @param lockStore      Delegate.
     * @param quotaStore     Delegate.
     * @param attributeStore Delegate.
     * @param jobUpdateStore Delegate.
     */
    WriteAheadStorage(TransactionManager transactionManager, SchedulerStore.Mutable schedulerStore,
            CronJobStore.Mutable jobStore, TaskStore.Mutable taskStore, LockStore.Mutable lockStore,
            QuotaStore.Mutable quotaStore, AttributeStore.Mutable attributeStore,
            JobUpdateStore.Mutable jobUpdateStore, Logger log, EventSink eventSink) {

        super(schedulerStore, jobStore, taskStore, lockStore, quotaStore, attributeStore, jobUpdateStore);

        this.transactionManager = requireNonNull(transactionManager);
        this.schedulerStore = requireNonNull(schedulerStore);
        this.jobStore = requireNonNull(jobStore);
        this.taskStore = requireNonNull(taskStore);
        this.lockStore = requireNonNull(lockStore);
        this.quotaStore = requireNonNull(quotaStore);
        this.attributeStore = requireNonNull(attributeStore);
        this.jobUpdateStore = requireNonNull(jobUpdateStore);
        this.log = requireNonNull(log);
        this.eventSink = requireNonNull(eventSink);
    }

    private void write(Op op) {
        Preconditions.checkState(transactionManager.hasActiveTransaction(),
                "Mutating operations must be within a transaction.");
        transactionManager.log(op);
    }

    @Override
    public void saveFrameworkId(final String frameworkId) {
        requireNonNull(frameworkId);

        write(Op.saveFrameworkId(new SaveFrameworkId(frameworkId)));
        schedulerStore.saveFrameworkId(frameworkId);
    }

    @Override
    public boolean unsafeModifyInPlace(final String taskId, final ITaskConfig taskConfiguration) {
        requireNonNull(taskId);
        requireNonNull(taskConfiguration);

        boolean mutated = taskStore.unsafeModifyInPlace(taskId, taskConfiguration);
        if (mutated) {
            write(Op.rewriteTask(new RewriteTask(taskId, taskConfiguration.newBuilder())));
        }
        return mutated;
    }

    @Override
    public void deleteTasks(final Set<String> taskIds) {
        requireNonNull(taskIds);

        write(Op.removeTasks(new RemoveTasks(taskIds)));
        taskStore.deleteTasks(taskIds);
    }

    @Override
    public void saveTasks(final Set<IScheduledTask> newTasks) {
        requireNonNull(newTasks);

        write(Op.saveTasks(new SaveTasks(IScheduledTask.toBuildersSet(newTasks))));
        taskStore.saveTasks(newTasks);
    }

    @Override
    public Optional<IScheduledTask> mutateTask(String taskId, Function<IScheduledTask, IScheduledTask> mutator) {

        Optional<IScheduledTask> mutated = taskStore.mutateTask(taskId, mutator);
        log.debug("Storing updated task to log: {}={}", taskId, mutated.get().getStatus());
        write(Op.saveTasks(new SaveTasks(ImmutableSet.of(mutated.get().newBuilder()))));

        return mutated;
    }

    @Override
    public void saveQuota(final String role, final IResourceAggregate quota) {
        requireNonNull(role);
        requireNonNull(quota);

        write(Op.saveQuota(new SaveQuota(role, quota.newBuilder())));
        quotaStore.saveQuota(role, quota);
    }

    @Override
    public boolean saveHostAttributes(final IHostAttributes attrs) {
        requireNonNull(attrs);

        boolean changed = attributeStore.saveHostAttributes(attrs);
        if (changed) {
            write(Op.saveHostAttributes(new SaveHostAttributes(attrs.newBuilder())));
            eventSink.post(new PubsubEvent.HostAttributesChanged(attrs));
        }
        return changed;
    }

    @Override
    public void removeJob(final IJobKey jobKey) {
        requireNonNull(jobKey);

        write(Op.removeJob(new RemoveJob().setJobKey(jobKey.newBuilder())));
        jobStore.removeJob(jobKey);
    }

    @Override
    public void saveAcceptedJob(final IJobConfiguration jobConfig) {
        requireNonNull(jobConfig);

        write(Op.saveCronJob(new SaveCronJob(jobConfig.newBuilder())));
        jobStore.saveAcceptedJob(jobConfig);
    }

    @Override
    public void removeQuota(final String role) {
        requireNonNull(role);

        write(Op.removeQuota(new RemoveQuota(role)));
        quotaStore.removeQuota(role);
    }

    @Override
    public void saveLock(final ILock lock) {
        requireNonNull(lock);

        write(Op.saveLock(new SaveLock(lock.newBuilder())));
        lockStore.saveLock(lock);
    }

    @Override
    public void removeLock(final ILockKey lockKey) {
        requireNonNull(lockKey);

        write(Op.removeLock(new RemoveLock(lockKey.newBuilder())));
        lockStore.removeLock(lockKey);
    }

    @Override
    public void saveJobUpdate(IJobUpdate update, Optional<String> lockToken) {
        requireNonNull(update);

        write(Op.saveJobUpdate(new SaveJobUpdate(update.newBuilder(), lockToken.orNull())));
        jobUpdateStore.saveJobUpdate(update, lockToken);
    }

    @Override
    public void saveJobUpdateEvent(IJobUpdateKey key, IJobUpdateEvent event) {
        requireNonNull(key);
        requireNonNull(event);

        write(Op.saveJobUpdateEvent(new SaveJobUpdateEvent(event.newBuilder(), key.newBuilder())));
        jobUpdateStore.saveJobUpdateEvent(key, event);
    }

    @Override
    public void saveJobInstanceUpdateEvent(IJobUpdateKey key, IJobInstanceUpdateEvent event) {
        requireNonNull(key);
        requireNonNull(event);

        write(Op.saveJobInstanceUpdateEvent(new SaveJobInstanceUpdateEvent(event.newBuilder(), key.newBuilder())));
        jobUpdateStore.saveJobInstanceUpdateEvent(key, event);
    }

    @Override
    public Set<IJobUpdateKey> pruneHistory(int perJobRetainCount, long historyPruneThresholdMs) {
        Set<IJobUpdateKey> prunedUpdates = jobUpdateStore.pruneHistory(perJobRetainCount, historyPruneThresholdMs);

        if (!prunedUpdates.isEmpty()) {
            // Pruned updates will eventually go away from persisted storage when a new snapshot is cut.
            // So, persisting pruning attempts is not strictly necessary as the periodic pruner will
            // provide eventual consistency between volatile and persistent storage upon scheduler
            // restart. By generating an out of band pruning during log replay the consistency is
            // achieved sooner without potentially exposing pruned but not yet persisted data.
            write(Op.pruneJobUpdateHistory(new PruneJobUpdateHistory(perJobRetainCount, historyPruneThresholdMs)));
        }
        return prunedUpdates;
    }

    @Override
    public void deleteAllTasks() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }

    @Override
    public void deleteHostAttributes() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }

    @Override
    public void deleteJobs() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }

    @Override
    public void deleteQuotas() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }

    @Override
    public void deleteLocks() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }

    @Override
    public void deleteAllUpdatesAndEvents() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }

    @Override
    public SchedulerStore.Mutable getSchedulerStore() {
        return this;
    }

    @Override
    public CronJobStore.Mutable getCronJobStore() {
        return this;
    }

    @Override
    public TaskStore.Mutable getUnsafeTaskStore() {
        return this;
    }

    @Override
    public LockStore.Mutable getLockStore() {
        return this;
    }

    @Override
    public QuotaStore.Mutable getQuotaStore() {
        return this;
    }

    @Override
    public AttributeStore.Mutable getAttributeStore() {
        return this;
    }

    @Override
    public TaskStore getTaskStore() {
        return this;
    }

    @Override
    public JobUpdateStore.Mutable getJobUpdateStore() {
        return this;
    }

    @Override
    public <T> T getUnsafeStoreAccess() {
        throw new UnsupportedOperationException(
                "Unsupported since casual storage users should never be doing this.");
    }
}