/** * 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 org.apache.hadoop.io; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; /** * Register for all FastWritable classes. The register stores mapping from class * serial id (2 bytes long String), to an instance of the class, which is used * to get a new instance of this class when deserializing objects. * * Server side hdfs code must ensure that each FastWritable class is registered * before any deserialization calls are made when serving client traffic. */ public final class FastWritableRegister { /** * Implementing classes can be serialized and deserialized much faster. All * implementing classes should be final. */ public interface FastWritable extends Writable { /** * Get a new instance of the class. Each call of this method should return a * distinct instance. */ public FastWritable getFastWritableInstance(Configuration conf); /** * Get name for this class used for fast serialization in the serialized form * using UTF8 encoding. The array contains two bytes which store the length of * the string. */ public byte[] getSerializedName(); } public static final Log LOG = LogFactory.getLog(FastWritableRegister.class .getName()); // length of the serial unique code for FastWritable classes private final static int NAME_LEN = 2; // maps serialVersionUi (String of length 2) to an instance of a class private final static Map<String, FastWritable> register = new ConcurrentHashMap<String, FastWritable>(); /** * Registers a FastWritable class for a given id (name). The names should be * unique, it is not possible to re-use a name for a different class. If we * re-register the same class, the object of the registered class must be the * same (the same reference). */ public static void register(FastWritableId id, FastWritable fw) { synchronized (FastWritableRegister.class) { String name = id.toString(); if (name.length() != NAME_LEN) { // we only allow two-byte serialization codes throw new RuntimeException("Code must be " + NAME_LEN + " bytes long"); } if (fw == null) { throw new RuntimeException("Instance cannot be null"); } FastWritable registeredWritable = register.get(name); if (registeredWritable != null && registeredWritable != fw) { throw new RuntimeException( "Trying to register different class with name: " + name); } else if (registeredWritable == fw) { return; //quietly } LOG.info("FastWritable - Registering name: " + name); register.put(name, fw); } } /** * Tries to get an instance given the name of class. If the name is registered * as FastWritable, the instance is obtained using the registry. */ public static FastWritable tryGetInstance(String name, Configuration conf) { if (name.length() != NAME_LEN) { // we use it to fast discard the request without doing map lookup return null; } FastWritable fw = register.get(name); return fw == null ? null : fw.getFastWritableInstance(conf); } public static boolean isVoidType(String name) { if (name.length() != NAME_LEN) { // we use it to fast discard the request return false; } return FastWritableId.SERIAL_VERSION_ID_VOID.toString().equals(name); } /** * Clear the register. */ static void clear() { register.clear(); } /** * Serial versions for all FastWritable classes. * Each id should be referred by a single class!!! */ public enum FastWritableId { SERIAL_VERSION_ID_1("AA"), SERIAL_VERSION_ID_2("AB"), SERIAL_VERSION_ID_3("AC"), SERIAL_VERSION_ID_4("AD"), SERIAL_VERSION_ID_5("AE"), // special id for returnable void SERIAL_VERSION_ID_VOID("VV"); private String name; FastWritableId(String name) { this.name = name; } public String toString() { return name; } } }