All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opensearch.common.util.MockPageCacheRecycler Maven / Gradle / Ivy

There is a newer version: 2.18.0
Show newest version
/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 */

/*
 * 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.
 */

/*
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

package org.opensearch.common.util;

import org.apache.lucene.tests.util.LuceneTestCase;
import org.opensearch.common.recycler.Recycler.V;
import org.opensearch.common.settings.Settings;
import org.opensearch.common.util.set.Sets;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static org.opensearch.test.OpenSearchTestCase.waitUntil;

public class MockPageCacheRecycler extends PageCacheRecycler {

    private static final ConcurrentMap ACQUIRED_PAGES = new ConcurrentHashMap<>();

    public static void ensureAllPagesAreReleased() throws Exception {
        final Map clusterManagerCopy = new HashMap<>(ACQUIRED_PAGES);
        if (!clusterManagerCopy.isEmpty()) {
            // not empty, we might be executing on a shared cluster that keeps on obtaining
            // and releasing pages, lets make sure that after a reasonable timeout, all cluster-manager
            // copy (snapshot) have been released
            final boolean success = waitUntil(() -> Sets.haveEmptyIntersection(clusterManagerCopy.keySet(), ACQUIRED_PAGES.keySet()));
            if (!success) {
                clusterManagerCopy.keySet().retainAll(ACQUIRED_PAGES.keySet());
                // remove all existing cluster-manager copy we will report on
                ACQUIRED_PAGES.keySet().removeAll(clusterManagerCopy.keySet());
                if (!clusterManagerCopy.isEmpty()) {
                    Iterator causes = clusterManagerCopy.values().iterator();
                    Throwable firstCause = causes.next();
                    RuntimeException exception = new RuntimeException(
                        clusterManagerCopy.size() + " pages have not been released",
                        firstCause
                    );
                    while (causes.hasNext()) {
                        exception.addSuppressed(causes.next());
                    }
                    throw exception;
                }
            }
        }
    }

    private final Random random;

    public MockPageCacheRecycler(Settings settings) {
        super(settings);
        // we always initialize with 0 here since we really only wanna have some random bytes / ints / longs
        // and given the fact that it's called concurrently it won't reproduces anyway the same order other than in a unittest
        // for the latter 0 is just fine
        random = new Random(0);
    }

    private  V wrap(final V v) {
        ACQUIRED_PAGES.put(v, new Throwable("Unreleased Page from test: " + LuceneTestCase.getTestClass().getName()));
        return new V() {

            @Override
            public void close() {
                final Throwable t = ACQUIRED_PAGES.remove(v);
                if (t == null) {
                    throw new IllegalStateException("Releasing a page that has not been acquired");
                }
                final T ref = v();
                if (ref instanceof Object[]) {
                    Arrays.fill((Object[]) ref, 0, Array.getLength(ref), null);
                } else if (ref instanceof byte[]) {
                    Arrays.fill((byte[]) ref, 0, Array.getLength(ref), (byte) random.nextInt(256));
                } else if (ref instanceof long[]) {
                    Arrays.fill((long[]) ref, 0, Array.getLength(ref), random.nextLong());
                } else if (ref instanceof int[]) {
                    Arrays.fill((int[]) ref, 0, Array.getLength(ref), random.nextInt());
                } else if (ref instanceof double[]) {
                    Arrays.fill((double[]) ref, 0, Array.getLength(ref), random.nextDouble() - 0.5);
                } else if (ref instanceof float[]) {
                    Arrays.fill((float[]) ref, 0, Array.getLength(ref), random.nextFloat() - 0.5f);
                } else {
                    for (int i = 0; i < Array.getLength(ref); ++i) {
                        Array.set(ref, i, (byte) random.nextInt(256));
                    }
                }
                v.close();
            }

            @Override
            public T v() {
                return v.v();
            }

            @Override
            public boolean isRecycled() {
                return v.isRecycled();
            }

        };
    }

    @Override
    public V bytePage(boolean clear) {
        final V page = super.bytePage(clear);
        if (!clear) {
            Arrays.fill(page.v(), 0, page.v().length, (byte) random.nextInt(1 << 8));
        }
        return wrap(page);
    }

    @Override
    public V intPage(boolean clear) {
        final V page = super.intPage(clear);
        if (!clear) {
            Arrays.fill(page.v(), 0, page.v().length, random.nextInt());
        }
        return wrap(page);
    }

    @Override
    public V longPage(boolean clear) {
        final V page = super.longPage(clear);
        if (!clear) {
            Arrays.fill(page.v(), 0, page.v().length, random.nextLong());
        }
        return wrap(page);
    }

    @Override
    public V objectPage() {
        return wrap(super.objectPage());
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy