/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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.elasticsearch.common.recycler; import org.elasticsearch.common.recycler.Recycler.V; import org.elasticsearch.test.ESTestCase; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public abstract class AbstractRecyclerTestCase extends ESTestCase { // marker states for data protected static final byte FRESH = 1; protected static final byte RECYCLED = 2; protected static final byte DEAD = 42; protected static final Recycler.C<byte[]> RECYCLER_C = new AbstractRecyclerC<byte[]>() { @Override public byte[] newInstance(int sizing) { byte[] value = new byte[10]; // "fresh" is intentionally not 0 to ensure we covered this code path Arrays.fill(value, FRESH); return value; } @Override public void recycle(byte[] value) { Arrays.fill(value, RECYCLED); } @Override public void destroy(byte[] value) { // we cannot really free the internals of a byte[], so mark it for verification Arrays.fill(value, DEAD); } }; protected void assertFresh(byte[] data) { assertNotNull(data); for (int i = 0; i < data.length; ++i) { assertEquals(FRESH, data[i]); } } protected void assertRecycled(byte[] data) { assertNotNull(data); for (int i = 0; i < data.length; ++i) { assertEquals(RECYCLED, data[i]); } } protected void assertDead(byte[] data) { assertNotNull(data); for (int i = 0; i < data.length; ++i) { assertEquals(DEAD, data[i]); } } protected abstract Recycler<byte[]> newRecycler(int limit); protected int limit = randomIntBetween(5, 10); public void testReuse() { Recycler<byte[]> r = newRecycler(limit); Recycler.V<byte[]> o = r.obtain(); assertFalse(o.isRecycled()); final byte[] b1 = o.v(); assertFresh(b1); o.close(); assertRecycled(b1); o = r.obtain(); final byte[] b2 = o.v(); if (o.isRecycled()) { assertRecycled(b2); assertSame(b1, b2); } else { assertFresh(b2); assertNotSame(b1, b2); } o.close(); r.close(); } public void testRecycle() { Recycler<byte[]> r = newRecycler(limit); Recycler.V<byte[]> o = r.obtain(); assertFresh(o.v()); random().nextBytes(o.v()); o.close(); o = r.obtain(); assertRecycled(o.v()); o.close(); r.close(); } public void testDoubleRelease() { final Recycler<byte[]> r = newRecycler(limit); final Recycler.V<byte[]> v1 = r.obtain(); v1.close(); try { v1.close(); } catch (IllegalStateException e) { // impl has protection against double release: ok return; } // otherwise ensure that the impl may not be returned twice final Recycler.V<byte[]> v2 = r.obtain(); final Recycler.V<byte[]> v3 = r.obtain(); assertNotSame(v2.v(), v3.v()); r.close(); } public void testDestroyWhenOverCapacity() { Recycler<byte[]> r = newRecycler(limit); // get & keep reference to new/recycled data Recycler.V<byte[]> o = r.obtain(); byte[] data = o.v(); assertFresh(data); // now exhaust the recycler List<V<byte[]>> vals = new ArrayList<>(limit); for (int i = 0; i < limit ; ++i) { vals.add(r.obtain()); } // Recycler size increases on release, not on obtain! for (V<byte[]> v: vals) { v.close(); } // release first ref, verify for destruction o.close(); assertDead(data); // close the rest r.close(); } public void testClose() { Recycler<byte[]> r = newRecycler(limit); // get & keep reference to pooled data Recycler.V<byte[]> o = r.obtain(); byte[] data = o.v(); assertFresh(data); // randomize & return to pool random().nextBytes(data); o.close(); // verify that recycle() ran assertRecycled(data); // closing the recycler should mark recycled instances via destroy() r.close(); assertDead(data); } }