/*
* 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.brooklyn.core.internal.storage.impl;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import org.apache.brooklyn.core.internal.storage.BrooklynStorage;
import org.apache.brooklyn.core.internal.storage.DataGrid;
import org.apache.brooklyn.core.internal.storage.Reference;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
public class BrooklynStorageImpl implements BrooklynStorage {
private final DataGrid datagrid;
private final ConcurrentMap<String, Object> refsMap;
private final ConcurrentMap<String, Object> listsMap;
private final ConcurrentMap<String, WeakReference<Reference<?>>> refsCache;
private final ConcurrentMap<String, WeakReference<Reference<?>>> listRefsCache;
public BrooklynStorageImpl(DataGrid datagrid) {
this.datagrid = datagrid;
this.refsMap = datagrid.getMap("refs");
this.listsMap = datagrid.getMap("lists");
this.refsCache = Maps.newConcurrentMap();
this.listRefsCache = Maps.newConcurrentMap();
}
/**
* Returns the DataGrid used by this BrooklynStorageImpl
*
* @return the DataGrid.
*/
@VisibleForTesting
public DataGrid getDataGrid() {
return datagrid;
}
@Override
public <T> Reference<T> getReference(final String id) {
// Can use different ref instances; no need to always return same one. Caching is an
// optimisation to just avoid extra object creation.
WeakReference<Reference<?>> weakRef = refsCache.get(id);
Reference<?> ref = (weakRef != null) ? weakRef.get() : null;
if (ref == null) {
ref = new BackedReference<T>(refsMap, id) {
@Override protected void finalize() {
// TODO Don't like using finalize due to performance overhead, but not
// optimising yet. Could use PhantomReference instead; see
// http://java.dzone.com/articles/finalization-and-phantom
refsCache.remove(id);
}
};
refsCache.putIfAbsent(id, new WeakReference<Reference<?>>(ref));
}
return (Reference<T>) ref;
}
@Override
public <T> Reference<List<T>> getNonConcurrentList(final String id) {
WeakReference<Reference<?>> weakRef = listRefsCache.get(id);
Reference<?> ref = (weakRef != null) ? weakRef.get() : null;
if (ref == null) {
ref = new BackedReference<List<T>>(listsMap, id) {
@Override public List<T> get() {
List<T> result = super.get();
return (result == null ? ImmutableList.<T>of() : Collections.unmodifiableList(result));
}
@Override protected void finalize() {
listRefsCache.remove(id);
}
};
listRefsCache.putIfAbsent(id, new WeakReference<Reference<?>>(ref));
}
return (Reference<List<T>>) ref;
}
@Override
public <K, V> ConcurrentMap<K, V> getMap(final String id) {
return datagrid.<K,V>getMap(id);
}
@Override
public void remove(String id) {
datagrid.remove(id);
refsMap.remove(id);
listsMap.remove(id);
refsCache.remove(id);
listRefsCache.remove(id);
}
@Override
public void terminate() {
datagrid.terminate();
}
public boolean isMostlyEmpty() {
if (!refsMap.isEmpty() || !listsMap.isEmpty())
return false;
// the datagrid may have some standard bookkeeping entries
return true;
}
@Override
public Map<String, Object> getStorageMetrics() {
return ImmutableMap.of(
"datagrid", datagrid.getDatagridMetrics(),
"refsMapSize", ""+refsMap.size(),
"listsMapSize", ""+listsMap.size());
}
@Override
public String toString() {
return super.toString() + getStorageMetrics();
}
}