/**
* Copyright 2011 LiveRamp
*
* 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 com.liveramp.hank.coordinator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import com.liveramp.hank.storage.RemoteDomainCleaner;
import com.liveramp.hank.storage.RemoteDomainVersionDeleter;
import com.liveramp.hank.storage.StorageEngine;
import com.liveramp.hank.storage.incremental.IncrementalDomainVersionProperties;
import com.liveramp.hank.util.ReverseComparator;
public final class Domains {
private static final Logger LOG = LoggerFactory.getLogger(Domains.class);
private Domains() {
}
public static long getTotalNumBytes(Domain domain) throws IOException {
long total = 0;
for (DomainVersion version : domain.getVersions()) {
if (version.isDefunct()) {
continue;
}
total += DomainVersions.getTotalNumBytes(version);
}
return total;
}
public static DomainVersion getLatestDelta(Domain domain) throws IOException {
SortedSet<DomainVersion> versions = domain.getVersions();
if (versions == null || versions.size() == 0) {
return null;
} else {
ArrayList<DomainVersion> list = Lists.newArrayList(versions);
Collections.reverse(list);
for (DomainVersion version : list) {
if(!isBase(version)){
return version;
}
}
return null;
}
}
public static DomainVersion getLatestVersion(Domain domain) throws IOException {
SortedSet<DomainVersion> versions = domain.getVersions();
if (versions == null || versions.size() == 0) {
return null;
} else {
return versions.last();
}
}
public static DomainVersion getLatestVersionNotOpenNotDefunct(Domain domain) throws IOException {
Set<DomainVersion> originalVersions = domain.getVersions();
if (originalVersions == null || originalVersions.size() == 0) {
return null;
}
SortedSet<DomainVersion> versions = new TreeSet<DomainVersion>(new ReverseComparator<DomainVersion>());
versions.addAll(originalVersions);
for (DomainVersion version : versions) {
if (isCompleteToBase(version, domain)) {
return version;
}
}
return null;
}
public static boolean hasOpenDelta(Domain domain) throws IOException {
return getLatestVersion(domain) != null && !allDeltasComplete(getLatestDelta(domain), domain);
}
private static boolean allDeltasComplete(DomainVersion version, Domain domain) throws IOException {
if(version == null){
return true;
}
if (isBase(version)) {
return true;
}
if (!DomainVersions.isClosed(version)) {
return false;
}
IncrementalDomainVersionProperties properties = (IncrementalDomainVersionProperties)version.getProperties();
return allDeltasComplete(
domain.getVersion(properties.getParentVersionNumber()),
domain
);
}
public static boolean hasOpenDeltaAfterLastValidBase(Domain domain) throws IOException {
final DomainVersion latestVersion = getLatestVersion(domain);
if (isCompleteToBase(latestVersion, domain)) {
return false;
} else {
return hasOpenDelta(domain);
}
}
public static Optional<DomainVersion> getLatestOpenDeltaIfExists(Domain domain) throws IOException {
final DomainVersion latestDelta = getLatestDelta(domain);
return hasOpenDelta(domain) ? Optional.fromNullable(latestDelta) : Optional.<DomainVersion>absent();
}
private static boolean isCompleteToBase(DomainVersion version, Domain domain) throws IOException {
if(version == null){
return true;
}
if (!DomainVersions.isClosed(version)) {
return false;
}
if (isBase(version)) {
return !version.isDefunct();
}
// TODO is there ever going to be a different impl of props?
IncrementalDomainVersionProperties properties = (IncrementalDomainVersionProperties)version.getProperties();
return isCompleteToBase(
domain.getVersion(properties.getParentVersionNumber()),
domain
);
}
private static boolean isBase(DomainVersion version) throws IOException {
IncrementalDomainVersionProperties properties = (IncrementalDomainVersionProperties)version.getProperties();
return properties.isBase();
}
public static void cleanDomains(Collection<Domain> domains, StorageEngine.RemoteLocation dataLocation) throws IOException {
cleanDomains(domains, true, dataLocation);
}
public static void cleanDomains(Collection <Domain> domains, boolean deleteMetadata, StorageEngine.RemoteLocation dataLocation) throws IOException {
for (Domain domain : domains) {
StorageEngine storageEngine = domain.getStorageEngine();
RemoteDomainCleaner cleaner = storageEngine.getRemoteDomainCleaner();
if (cleaner == null) {
LOG.info("Failed to clean Domain " + domain.getName() + ". No Remote Domain Cleaner is configured.");
continue;
}
RemoteDomainVersionDeleter deleter = storageEngine.getRemoteDomainVersionDeleter(dataLocation);
if (deleter == null) {
LOG.info("Failed to clean Domain " + domain.getName() + ". No Remote Domain Version Deleter is configured.");
continue;
}
LOG.info("Cleaning Domain " + domain.getName());
cleaner.deleteOldVersions(deleter, deleteMetadata);
}
}
}