/**
* 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.backup;
import java.util.Set;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import org.apache.aurora.common.util.BuildInfo;
import org.apache.aurora.common.util.testing.FakeClock;
import org.apache.aurora.gen.storage.Snapshot;
import org.apache.aurora.scheduler.base.Query;
import org.apache.aurora.scheduler.base.Tasks;
import org.apache.aurora.scheduler.storage.SnapshotStore;
import org.apache.aurora.scheduler.storage.Storage;
import org.apache.aurora.scheduler.storage.Storage.MutateWork.NoResult;
import org.apache.aurora.scheduler.storage.db.DbUtil;
import org.apache.aurora.scheduler.storage.db.EnumBackfill;
import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
import org.apache.aurora.scheduler.storage.log.SnapshotStoreImpl;
import org.apache.aurora.scheduler.storage.log.ThriftBackfill;
import static java.util.Objects.requireNonNull;
import static org.apache.aurora.common.util.testing.FakeBuildInfo.generateBuildInfo;
/**
* A short-lived in-memory storage system that can be converted to a {@link Snapshot}.
*/
interface TemporaryStorage {
/**
* Deletes all tasks matching a query. Deleted tasks will not be reflected in the snapshot when
* {@link #toSnapshot()} is executed.
*
* @param query Query builder for tasks to delete.
*/
void deleteTasks(Query.Builder query);
/**
* Fetches tasks matching a query.
*
* @param query Query builder for tasks to fetch.
* @return Matching tasks.
*/
Iterable<IScheduledTask> fetchTasks(Query.Builder query);
/**
* Creates a snapshot of the contents of the temporary storage.
*
* @return Temporary storage snapshot.
*/
Snapshot toSnapshot();
/**
* A factory that creates temporary storage instances, detached from the rest of the system.
*/
class TemporaryStorageFactory implements Function<Snapshot, TemporaryStorage> {
private final ThriftBackfill thriftBackfill;
private final EnumBackfill enumBackfill;
@Inject
TemporaryStorageFactory(ThriftBackfill thriftBackfill, EnumBackfill enumBackfill) {
this.thriftBackfill = requireNonNull(thriftBackfill);
this.enumBackfill = requireNonNull(enumBackfill);
}
@Override
public TemporaryStorage apply(Snapshot snapshot) {
final Storage storage = DbUtil.createFlaggedStorage();
final BuildInfo buildInfo = generateBuildInfo();
FakeClock clock = new FakeClock();
clock.setNowMillis(snapshot.getTimestamp());
final SnapshotStore<Snapshot> snapshotStore = new SnapshotStoreImpl(
buildInfo,
clock,
storage,
// Safe to pass false here to default to the non-experimental task store
// during restore from backup procedure.
false /** useDbSnapshotForTaskStore */,
// Safe to pass empty set here because during backup restore we are not deciding which
// fields to write to the snapshot.
ImmutableSet.of() /** hydrateFields */,
// We can just pass an empty lambda for the MigrationManager as migration is a no-op
// when restoring from backup.
() -> { } /** migrationManager */,
thriftBackfill,
enumBackfill);
snapshotStore.applySnapshot(snapshot);
return new TemporaryStorage() {
@Override
public void deleteTasks(final Query.Builder query) {
storage.write((NoResult.Quiet) storeProvider -> {
Set<String> ids = FluentIterable.from(storeProvider.getTaskStore().fetchTasks(query))
.transform(Tasks::id)
.toSet();
storeProvider.getUnsafeTaskStore().deleteTasks(ids);
});
}
@Override
public Iterable<IScheduledTask> fetchTasks(final Query.Builder query) {
return storage.read(storeProvider -> storeProvider.getTaskStore().fetchTasks(query));
}
@Override
public Snapshot toSnapshot() {
return snapshotStore.createSnapshot();
}
};
}
}
}