/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.qp.storeadapter.indexrow; import com.foundationdb.qp.operator.StoreAdapter; import com.foundationdb.qp.row.IndexRow; import com.foundationdb.qp.rowtype.IndexRowType; import com.foundationdb.server.util.LRUCacheMap; import java.util.*; public class IndexRowPool { public IndexRow takeIndexRow(StoreAdapter adapter, IndexRowType indexRowType) { return adapterPool(adapter).takeIndexRow(indexRowType); } public void returnIndexRow(StoreAdapter adapter, IndexRowType indexRowType, IndexRow indexRow) { adapterPool(adapter).returnIndexRow(indexRowType, indexRow); } public IndexRowPool() { } // For use by this class private AdapterPool adapterPool(StoreAdapter adapter) { LRUCacheMap<Long, AdapterPool> adapterPool = threadAdapterPools.get(); AdapterPool pool = adapterPool.get(adapter.id()); if (pool == null) { pool = new AdapterPool(adapter); adapterPool.put(adapter.id(), pool); } return pool; } // Class state private static final int CAPACITY_PER_THREAD = 10; // Object state private final ThreadLocal<LRUCacheMap<Long, AdapterPool>> threadAdapterPools = new ThreadLocal<LRUCacheMap<Long, AdapterPool>>() { @Override protected LRUCacheMap<Long, AdapterPool> initialValue() { return new LRUCacheMap<>(CAPACITY_PER_THREAD); } }; // Inner classes private static class AdapterPool { public IndexRow takeIndexRow(IndexRowType indexRowType) { IndexRow indexRow = null; Deque<IndexRow> indexRows = indexRowCache.get(indexRowType); if (indexRows != null && !indexRows.isEmpty()) { indexRow = indexRows.removeLast(); indexRow.reset(); } if (indexRow == null) { indexRow = adapter.newIndexRow(indexRowType); } return indexRow; } public void returnIndexRow(IndexRowType indexRowType, IndexRow indexRow) { Deque<IndexRow> indexRows = indexRowCache.get(indexRowType); if (indexRows == null) { indexRows = new ArrayDeque<>(); indexRowCache.put(indexRowType, indexRows); } assert !indexRows.contains(indexRow); indexRows.addLast(indexRow); } public AdapterPool(StoreAdapter adapter) { this.adapter = adapter; } private final StoreAdapter adapter; private final Map<IndexRowType, Deque<IndexRow>> indexRowCache = new HashMap<>(); } }