/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { benchmarkDuration, benchmarkIt } from "@fluid-tools/benchmark";
import { createChildLogger } from "@fluidframework/telemetry-utils/internal";
import { GCNodeType, GarbageCollector, } from "../../gc/index.js";
import { pkgVersion } from "../../packageVersion.js";
import { parseNothing } from "./gcUnitTestHelpers.js";
function createGarbageCollector(gcOptions) {
    const getNodeType = (nodePath) => {
        if (nodePath.split("/").length !== 2) {
            return GCNodeType.Other;
        }
        return GCNodeType.DataStore;
    };
    // The runtime to be passed to the garbage collector.
    const gcRuntime = {
        getGCData: async () => {
            return { gcNodes: {} };
        },
        updateUsedRoutes: (usedRoutes) => {
            return { totalNodeCount: 0, unusedNodeCount: 0 };
        },
        deleteSweepReadyNodes: (sweepReadyRoutes) => {
            return [];
        },
        updateTombstonedRoutes: (tombstoneRoutes) => { },
        getNodeType,
        getCurrentReferenceTimestampMs: () => Date.now(),
        closeFn: () => { },
    };
    return GarbageCollector.create({
        runtime: gcRuntime,
        gcOptions,
        baseSnapshot: undefined,
        baseLogger: createChildLogger({}),
        existing: false,
        metadata: undefined,
        createContainerMetadata: {
            createContainerRuntimeVersion: pkgVersion,
            createContainerTimestamp: Date.now(),
        },
        isSummarizerClient: true,
        readAndParseBlob: parseNothing,
        getNodePackagePath: async (nodeId) => ["gcBenchmarkTestPkg"],
        getLastSummaryTimestampMs: () => Date.now(),
        submitMessage: (message) => { },
    });
}
describe("GC benchmark tests", () => {
    describe("initializeOrUpdateGCState", () => {
        const inactiveTimeoutMs = 100;
        /**
         * Sets up the garbage collector to have unreferenced nodes that will be updated
         * in the benchmark tests.
         */
        const setup = async (unrefNodeCount) => {
            const gc = createGarbageCollector({ inactiveTimeoutMs });
            const currentTime = Date.now();
            // Set the unreferenced timestamp to older than inactive timeout so that the nodes start
            // as inactive.
            const unreferencedTimestampMs = currentTime - (inactiveTimeoutMs + 10);
            // Generate a base snapshot that has `unrefNodeCount` number of unreferenced nodes
            // and all are inactive.
            const gcState = { gcNodes: {} };
            for (let i = 0; i < unrefNodeCount; i++) {
                gcState.gcNodes[`node${i}`] = {
                    outboundRoutes: [],
                    unreferencedTimestampMs,
                };
            }
            const baseSnapshot = {
                gcState,
                tombstones: [],
                deletedNodes: [],
            };
            // Override the base snapshot promise to return the above snapshot.
            gc.baseSnapshotDataP = Promise.resolve(baseSnapshot);
            // Call initializeOrUpdateGCState once so that it initializes the GC state from the
            // base snapshot. The calls to initializeOrUpdateGCState after this one happens on
            // every connection and that's the one we are benchmarking
            await gc.initializeOrUpdateGCState();
            return gc;
        };
        /**
         * These tests benchmark how long it takes for the initializeOrUpdateGCState function to run
         * when there are a high number of unreferenced nodes. Since this results in clearing and
         * setting of timers, it takes a long time and can cause slow downs.
         */
        benchmarkIt({
            title: "5000 unref nodes",
            ...benchmarkDuration({
                benchmarkFnCustom: async (state) => {
                    const gc = await setup(5000 /* unrefNodeCount */);
                    await state.timeAllBatchesAsync(async () => {
                        await gc.initializeOrUpdateGCState();
                    });
                    gc.dispose();
                },
            }),
        });
        benchmarkIt({
            title: "15000 unref nodes",
            ...benchmarkDuration({
                benchmarkFnCustom: async (state) => {
                    const gc = await setup(15000 /* unrefNodeCount */);
                    await state.timeAllBatchesAsync(async () => {
                        await gc.initializeOrUpdateGCState();
                    });
                    gc.dispose();
                },
            }),
        });
        benchmarkIt({
            title: "30000 unref nodes",
            ...benchmarkDuration({
                benchmarkFnCustom: async (state) => {
                    const gc = await setup(30000 /* unrefNodeCount */);
                    await state.timeAllBatchesAsync(async () => {
                        await gc.initializeOrUpdateGCState();
                    });
                    gc.dispose();
                },
            }),
        });
    });
});
//# sourceMappingURL=gc.perf.spec.js.map