/**
* 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.deephacks.confit.serialization;
import com.google.common.base.Strings;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
/**
* UniqueIds are used when beans are serialized into binary form. Every persistent bean manager implementation
* should provide an implementation that is registered using the standard java ServiceLoader mechanism.
*
* Instance ids and schema/property names are mapped to a unique id numbers in order to save space and
* decrease serialization latency. Schema and property names are always cached in memory to speedup lookup.
* Instance ids can also be cached but this decision is taken by the implementation.
*/
public abstract class UniqueIds {
protected boolean shouldCacheInstance;
private final ConcurrentHashMap<String, Long> instanceIdCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, String> instanceNameCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Integer> schemaIdCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, String> schemaNameCache = new ConcurrentHashMap<>();
protected UniqueIds(boolean shouldCacheInstance) {
this.shouldCacheInstance = shouldCacheInstance;
}
public static UniqueIds lookup() {
Iterator<UniqueIds> loader = ServiceLoader.load(UniqueIds.class).iterator();
if (loader.hasNext()) {
return loader.next();
}
throw new IllegalStateException("Could not find a UniqueIds service in META-INF/services.");
}
public byte[] getMaxSchemaWidth() {
return Bytes.fromInt(-1);
}
public byte[] getMinSchemaWidth() {
return Bytes.fromInt(0);
}
public byte[] getMaxInstanceWidth() {
return Bytes.fromLong(-1);
}
public byte[] getMinInstanceWidth() {
return Bytes.fromLong(0);
}
public int getSchemaId(final String name) {
Integer id = schemaIdCache.get(name);
if (id != null) {
return id;
} else {
id = getSchemaIdFromStorage(name);
schemaIdCache.put(name, id);
schemaNameCache.put(id, name);
}
return id;
}
public String getSchemaName(final int id) {
String name = schemaNameCache.get(id);
if (!Strings.isNullOrEmpty(name)) {
return name;
} else {
name = getSchemaNameFromStorage(id);
if (Strings.isNullOrEmpty(name)) {
throw new IllegalStateException("Could not map id " + id + " to a name");
}
schemaIdCache.put(name, id);
schemaNameCache.put(id, name);
}
return name;
}
public long getInstanceId(final String name) {
Long id = instanceIdCache.get(name);
if (id != null) {
return id;
} else {
id = getInstanceIdFromStorage(name);
if (shouldCacheInstance) {
instanceIdCache.put(name, id);
instanceNameCache.put(id, name);
}
}
return id;
}
public String getInstanceName(final long id) {
String name = instanceNameCache.get(id);
if (!Strings.isNullOrEmpty(name)) {
return name;
} else {
name = getInstanceNameFromStorage(id);
if (Strings.isNullOrEmpty(name)) {
throw new IllegalStateException("Could not map id " + id + " to a name");
}
if (shouldCacheInstance) {
instanceIdCache.put(name, id);
instanceNameCache.put(id, name);
}
}
return name;
}
protected abstract String getSchemaNameFromStorage(int id);
protected abstract int getSchemaIdFromStorage(String name);
protected abstract String getInstanceNameFromStorage(long id);
protected abstract long getInstanceIdFromStorage(String name);
}