/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.pinterest.terrapin.zookeeper; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.pinterest.terrapin.TerrapinUtil; import com.pinterest.terrapin.thrift.generated.Options; import com.pinterest.terrapin.thrift.generated.PartitionerType; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.List; /** * The information as stored for a file set inside zookeeper. We store these * as json strings. This provides the bridge between logical names such as "recommendation_data" * etc. to actual files on HDFS. File sets refer to a collection of versions of a set of * (h)files. Each version of the file set is an HDFS directory. The FileSetInfo * contains information such as the current serving HDFS directory, the number of * partitions in the current serving HDFS directory and the set of HDFS directories * to be retained through garbage collection etc. This information is used by the * controller to determine which HDFS directories/helix resources need to be cleaned up * or retained. Its also used by the client to quickly find the active serving HDFS * resource for a file set and find the partitioner type/number of partitions etc. */ public class FileSetInfo { private static final Logger LOG = LoggerFactory.getLogger(FileSetInfo.class); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static class ServingInfo { @JsonProperty("hdfsPath") public String hdfsPath; @JsonProperty("helixResource") public String helixResource; @JsonProperty("numPartitions") public int numPartitions; @JsonProperty("partitionerType") public PartitionerType partitionerType; @JsonCreator public ServingInfo(@JsonProperty("hdfsPath") String hdfsPath, @JsonProperty("helixResource") String helixResource, @JsonProperty("numPartitions") int numPartitions, @JsonProperty("partitionerType") PartitionerType partitionerType) { this.hdfsPath = Preconditions.checkNotNull(hdfsPath); this.helixResource = Preconditions.checkNotNull(helixResource); this.numPartitions = numPartitions; this.partitionerType = partitionerType; } @Override public boolean equals(Object o) { if (!(o instanceof ServingInfo)) { return false; } ServingInfo s = (ServingInfo)o; String hdfsPath1 = (this.hdfsPath == null) ? "" : this.hdfsPath; String hdfsPath2 = (s.hdfsPath == null) ? "" : s.hdfsPath; String helixResource1 = (this.helixResource == null) ? "" : this.helixResource; String helixResource2 = (s.helixResource == null) ? "" : s.helixResource; return hdfsPath1.equals(hdfsPath2) && helixResource1.equals(helixResource2) && s.numPartitions == this.numPartitions && s.partitionerType == this.partitionerType; } } public String fileSetName; public int numVersionsToKeep; // The current active HDFS path which is serving. public ServingInfo servingInfo; // List of HDFS paths which have made it into serving. This // value depends on @numVersionsToKeep. It lists the earlier versions // which were being served. public List<ServingInfo> oldServingInfoList; // Sometimes, transient objects may be created public boolean valid; // For Garbage Collection public boolean deleted; public FileSetInfo() { this.oldServingInfoList = Lists.newArrayList(); this.valid = false; this.deleted = false; } public FileSetInfo(String fileSetName, String hdfsDir, int numPartitions, List<ServingInfo> oldServingInfoList, Options options) { this.fileSetName = fileSetName; this.numVersionsToKeep = options.getNumVersionsToKeep(); this.oldServingInfoList = oldServingInfoList; this.servingInfo = new ServingInfo(hdfsDir, TerrapinUtil.hdfsDirToHelixResource(hdfsDir), numPartitions, options.getPartitioner()); this.valid = true; this.deleted = false; } public byte[] toJson() throws Exception { return OBJECT_MAPPER.writeValueAsBytes(this); } /** * To pretty printing JSON format. * @return JSON string * @throws IOException if dumping process raises any exceptions */ public String toPrettyPrintingJson() throws IOException { return OBJECT_MAPPER.defaultPrettyPrintingWriter().writeValueAsString(this); } public static FileSetInfo fromJson(byte[] json) throws Exception { return OBJECT_MAPPER.readValue(json, FileSetInfo.class); } @Override public boolean equals(Object o) { if (!(o instanceof FileSetInfo)) { return false; } FileSetInfo f = (FileSetInfo)o; String fileSetName1 = this.fileSetName == null ? "" : this.fileSetName; String fileSetName2 = f.fileSetName == null ? "" : f.fileSetName; if ((f.servingInfo == null && this.servingInfo != null) || (f.servingInfo != null && this.servingInfo == null)) { return false; } return fileSetName1.equals(fileSetName2) && f.numVersionsToKeep == this.numVersionsToKeep && ((f.servingInfo == null && this.servingInfo == null) || f.servingInfo.equals(this.servingInfo)) && ((f.oldServingInfoList == null && this.oldServingInfoList == null)) || f.oldServingInfoList.equals(this.oldServingInfoList) && f.deleted == this.deleted; } }