/* * 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.ignite.internal.binary; import org.jetbrains.annotations.Nullable; import java.util.HashMap; /** * Binary schema registry. Contains all well-known object schemas. * <p> * We rely on the fact that usually object has only few different schemas. For this reason we inline several * of them with optional fallback to normal hash map lookup. * */ public class BinarySchemaRegistry { /** Empty schema ID. */ private static final int EMPTY = 0; /** Whether registry still works in inline mode. */ private volatile boolean inline = true; /** First schema ID. */ private int schemaId1; /** Second schema ID. */ private int schemaId2; /** Third schema ID. */ private int schemaId3; /** Fourth schema ID. */ private int schemaId4; /** First schema. */ private BinarySchema schema1; /** Second schema. */ private BinarySchema schema2; /** Third schema. */ private BinarySchema schema3; /** Fourth schema. */ private BinarySchema schema4; /** Schemas with COW semantics. */ private volatile HashMap<Integer, BinarySchema> schemas; /** * Get schema for the given ID. We rely on very relaxed memory semantics here assuming that it is not critical * to return false-positive {@code null} values. * * @param schemaId Schema ID. * @return Schema or {@code null}. */ @Nullable public BinarySchema schema(int schemaId) { if (inline) { if (schemaId == schemaId1) return schema1; else if (schemaId == schemaId2) return schema2; else if (schemaId == schemaId3) return schema3; else if (schemaId == schemaId4) return schema4; } else { HashMap<Integer, BinarySchema> schemas0 = schemas; // Null can be observed here due to either data race or race condition when switching to non-inlined mode. // Both of them are benign for us because they lead only to unnecessary schema re-calc. if (schemas0 != null) return schemas0.get(schemaId); } return null; } /** * Add schema. * * @param schemaId Schema ID. * @param schema Schema. */ public void addSchema(int schemaId, BinarySchema schema) { synchronized (this) { if (inline) { // Check if this is already known schema. if (schemaId == schemaId1 || schemaId == schemaId2 || schemaId == schemaId3 || schemaId == schemaId4) return; // Try positioning new schema in inline mode. if (schemaId1 == EMPTY) { schemaId1 = schemaId; schema1 = schema; inline = true; // Forcing HB edge just in case. return; } if (schemaId2 == EMPTY) { schemaId2 = schemaId; schema2 = schema; inline = true; // Forcing HB edge just in case. return; } if (schemaId3 == EMPTY) { schemaId3 = schemaId; schema3 = schema; inline = true; // Forcing HB edge just in case. return; } if (schemaId4 == EMPTY) { schemaId4 = schemaId; schema4 = schema; inline = true; // Forcing HB edge just in case. return; } // No luck, switching to hash map mode. HashMap<Integer, BinarySchema> newSchemas = new HashMap<>(); newSchemas.put(schemaId1, schema1); newSchemas.put(schemaId2, schema2); newSchemas.put(schemaId3, schema3); newSchemas.put(schemaId4, schema4); newSchemas.put(schemaId, schema); schemas = newSchemas; inline = false; } else { HashMap<Integer, BinarySchema> newSchemas = new HashMap<>(schemas); newSchemas.put(schemaId, schema); schemas = newSchemas; } } } }