/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.common.buffer.impl; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import org.teiid.common.buffer.Cache; import org.teiid.common.buffer.CacheEntry; import org.teiid.common.buffer.FileStore; import org.teiid.common.buffer.Serializer; public class MemoryStorageManager implements Cache<Long> { public static final int MAX_FILE_SIZE = 1 << 17; private final class MemoryFileStore extends FileStore { private ByteBuffer buffer = ByteBuffer.allocate(MAX_FILE_SIZE); public MemoryFileStore() { buffer.limit(0); } @Override public synchronized void removeDirect() { removed.incrementAndGet(); buffer = ByteBuffer.allocate(0); } @Override protected synchronized int readWrite(long fileOffset, byte[] b, int offSet, int length, boolean write) { if (!write) { if (fileOffset >= getLength()) { return -1; } int position = (int)fileOffset; buffer.position(position); length = Math.min(length, (int)getLength() - position); buffer.get(b, offSet, length); return length; } int requiredLength = (int)(fileOffset + length); if (requiredLength > buffer.limit()) { buffer.limit(requiredLength); } buffer.position((int)fileOffset); buffer.put(b, offSet, length); return length; } @Override public synchronized void setLength(long length) { buffer.limit((int)length); } @Override public synchronized long getLength() { return buffer.limit(); } } private Map<Long, Map<Long, CacheEntry>> groups = new ConcurrentHashMap<Long, Map<Long, CacheEntry>>(); private AtomicInteger created = new AtomicInteger(); private AtomicInteger removed = new AtomicInteger(); public void initialize() { } @Override public FileStore createFileStore(String name) { created.incrementAndGet(); return new MemoryFileStore(); } public int getCreated() { return created.get(); } public int getRemoved() { return removed.get(); } @Override public boolean add(CacheEntry entry, Serializer<?> s) { Map<Long, CacheEntry> group = groups.get(s.getId()); if (group != null) { group.put(entry.getId(), entry); } return true; } @Override public boolean addToCacheGroup(Long gid, Long oid) { Map<Long, CacheEntry> group = groups.get(gid); if (group != null) { group.put(oid, null); return true; } return false; } @Override public void createCacheGroup(Long gid) { groups.put(gid, Collections.synchronizedMap(new HashMap<Long, CacheEntry>())); } @Override public Long lockForLoad(Long oid, Serializer<?> serializer) { return oid; } @Override public void unlockForLoad(Long o) { //nothing to do no locking } @Override public CacheEntry get(Long lock, Long oid, WeakReference<? extends Serializer<?>> ref) throws Exception { Map<Long, CacheEntry> group = groups.get(ref.get().getId()); if (group != null) { return group.get(oid); } return null; } @Override public boolean remove(Long gid, Long id) { Map<Long, CacheEntry> group = groups.get(gid); if (group != null) { synchronized (group) { int size = group.size(); group.remove(id); return group.size() != size; } } return false; } @Override public Collection<Long> removeCacheGroup(Long gid) { Map<Long, CacheEntry> group = groups.remove(gid); if (group == null) { return Collections.emptySet(); } synchronized (group) { return new ArrayList<Long>(group.keySet()); } } @Override public void shutdown() { } }