/*!
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed 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.
 */
import { EventEmitter } from 'events';
import PQueue from 'p-queue';
import { Database } from './database';
import { Session } from './session';
import { Transaction } from './transaction';
import { NormalCallback } from './common';
import { GoogleError, grpc } from 'google-gax';
import trace = require('stack-trace');
import { ObservabilityOptions } from './instrument';
import { GetSessionCallback } from './session-factory';
/**
 * @callback SessionPoolCloseCallback
 * @param {?Error} error Closing error, if any.
 */
export interface SessionPoolCloseCallback {
    (error?: SessionLeakError): void;
}
/** @deprecated. Use GetSessionCallback instead. */
export type GetReadSessionCallback = NormalCallback<Session>;
/** @deprecated. Use GetSessionCallback instead. */
export interface GetWriteSessionCallback {
    (err: Error | null, session?: Session | null, transaction?: Transaction | null): void;
}
/**
 * Interface for implementing custom session pooling logic, it should extend the
 * {@link https://nodejs.org/api/events.html|EventEmitter} class and emit any
 * asynchronous errors via an error event.
 *
 * @interface SessionPoolInterface
 * @extends external:{@link https://nodejs.org/api/events.html|EventEmitter}
 */
/**
 * @constructs SessionPoolInterface
 * @param {Database} database The database to create a pool for.
 */
export interface SessionPoolInterface extends EventEmitter {
    /**
     * Will be called via {@link Database#close}. Indicates that the pool should
     * perform any necessary teardown actions to its resources.
     *
     * @name SessionPoolInterface#close
     * @param {SessionPoolCloseCallback} callback The callback function.
     */
    /**
     * Will be called by the Database object, should be used to start creating
     * sessions/etc.
     *
     * @name SessionPoolInterface#open
     */
    /**
     * When called returns a session.
     *
     * @name SessionPoolInterface#getSession
     * @param {GetSessionCallback} callback The callback function.
     */
    /**
     * When called returns a session.
     *
     * @deprecated Use getSession instead.
     * @name SessionPoolInterface#getReadSession
     * @param {GetReadSessionCallback} callback The callback function.
     */
    /**
     * When called returns a session.
     *
     * @deprecated Use getSession instead.
     * @name SessionPoolInterface#getWriteSession
     * @param {GetWriteSessionCallback} callback The callback function.
     */
    /**
     * To be called when releasing a session back into the pool.
     *
     * @name SessionPoolInterface#release
     * @param {Session} session The session to be released.
     */
    close(callback: SessionPoolCloseCallback): void;
    open(): void;
    getSession(callback: GetSessionCallback): void;
    getReadSession(callback: GetReadSessionCallback): void;
    getWriteSession(callback: GetWriteSessionCallback): void;
    release(session: Session): void;
}
/**
 * Session pool configuration options.
 *
 * @typedef {object} SessionPoolOptions
 * @property {number} [acquireTimeout=Infinity] Time in milliseconds before
 *     giving up trying to acquire a session. If the specified value is
 *     `Infinity`, a timeout will not occur.
 * @property {number} [concurrency=Infinity] How many concurrent requests the pool is
 *     allowed to make.
 * @property {boolean} [fail=false] If set to true, an error will be thrown when
 *     there are no available sessions for a request.
 * @property {number} [idlesAfter=10] How long until a resource becomes idle, in
 *     minutes.
 * @property {number} [keepAlive=30] How often to ping idle sessions, in
 *     minutes. Must be less than 1 hour.
 * @property {Object<string, string>} [labels] Labels to apply to any session
 *     created by the pool.
 * @property {number} [max=100] Maximum number of resources to create at any
 *     given time.
 * @property {number} [maxIdle=1] Maximum number of idle resources to keep in
 *     the pool at any given time.
 * @property {number} [min=25] Minimum number of resources to keep in the pool at
 *     any given time.
 * @property {number} [writes=0.0]. Deprecated.
 * @property {number} [incStep=25] The number of new sessions to create when at
 *     least one more session is needed.
 */
export interface SessionPoolOptions {
    acquireTimeout?: number;
    concurrency?: number;
    fail?: boolean;
    idlesAfter?: number;
    keepAlive?: number;
    /**
     * @deprecated Use SpannerOptions.sessionLabels instead.
     */
    labels?: {
        [label: string]: string;
    };
    max?: number;
    maxIdle?: number;
    min?: number;
    /**
     * @deprecated. Starting from v6.5.0 the same session can be reused for
     * different types of transactions.
     */
    writes?: number;
    incStep?: number;
    /**
     * @deprecated Use Database constructor to pass databaseRole.
     */
    databaseRole?: string | null;
}
/**
 * Error to be thrown when attempting to release unknown resources.
 *
 * @private
 */
export declare class ReleaseError extends GoogleError {
    resource: unknown;
    constructor(resource: unknown);
}
/**
 * Error to be thrown when session leaks are detected.
 *
 * @private
 */
export declare class SessionLeakError extends GoogleError {
    messages: string[];
    constructor(leaks: string[]);
}
/**
 * Error to be thrown when the session pool is exhausted.
 */
export declare class SessionPoolExhaustedError extends GoogleError {
    messages: string[];
    constructor(leaks: string[]);
}
/**
 * Checks whether the given error is a 'Session not found' error.
 * @param error the error to check
 * @return true if the error is a 'Session not found' error, and otherwise false.
 */
export declare function isSessionNotFoundError(error: grpc.ServiceError | undefined): boolean;
interface SessionInventory {
    sessions: Session[];
    borrowed: Set<Session>;
}
/** @deprecated. */
export interface CreateSessionsOptions {
    writes?: number;
    reads?: number;
}
/**
 * Class used to manage connections to Spanner.
 *
 * **You don't need to use this class directly, connections will be handled for
 * you.**
 *
 * @class
 * @extends {EventEmitter}
 */
export declare class SessionPool extends EventEmitter implements SessionPoolInterface {
    database: Database;
    isOpen: boolean;
    options: SessionPoolOptions;
    _acquires: PQueue;
    _evictHandle: NodeJS.Timer;
    _inventory: SessionInventory;
    _onClose: Promise<void>;
    _pending: number;
    _waiters: number;
    _pingHandle: NodeJS.Timer;
    _requests: PQueue;
    _traces: Map<string, trace.StackFrame[]>;
    _observabilityOptions?: ObservabilityOptions;
    /**
     * Formats stack trace objects into Node-like stack trace.
     *
     * @param {object[]} trace The trace object.
     * @return {string}
     */
    static formatTrace(frames: trace.StackFrame[]): string;
    /**
     * Total number of available sessions.
     * @type {number}
     */
    get available(): number;
    /** @deprecated Starting from v6.5.0 the same session can be reused for
     * different types of transactions.
     */
    get currentWriteFraction(): number;
    /**
     * Total number of borrowed sessions.
     * @type {number}
     */
    get borrowed(): number;
    /**
     * Flag to determine if Pool is full.
     * @type {boolean}
     */
    get isFull(): boolean;
    /** @deprecated Use `size()` instead. */
    get reads(): number;
    /**
     * Total size of pool.
     * @type {number}
     */
    get size(): number;
    /** @deprecated Use `size()` instead. */
    get writes(): number;
    /** @deprecated Starting v6.5.0 the pending prepare state is obsolete. */
    get pendingPrepare(): number;
    /**
     * Number of sessions being created or prepared for a read/write transaction.
     * @type {number}
     */
    get totalPending(): number;
    /** @deprecated Use totalWaiters instead. */
    get numReadWaiters(): number;
    /** @deprecated Use totalWaiters instead. */
    get numWriteWaiters(): number;
    /**
     * Sum of read and write waiters.
     * @type {number}
     */
    get totalWaiters(): number;
    /**
     * @constructor
     * @param {Database} database The DB instance.
     * @param {SessionPoolOptions} [options] Configuration options.
     */
    constructor(database: Database, options?: SessionPoolOptions);
    /**
     * Closes and the pool.
     *
     * @emits SessionPool#close
     * @param {SessionPoolCloseCallback} callback The callback function.
     */
    close(callback: SessionPoolCloseCallback): void;
    /**
     * Retrieve a read session.
     *
     * @deprecated Use getSession instead.
     * @param {GetReadSessionCallback} callback The callback function.
     */
    getReadSession(callback: GetReadSessionCallback): void;
    /**
     * Retrieve a read/write session.
     *
     * @deprecated use getSession instead.
     * @param {GetWriteSessionCallback} callback The callback function.
     */
    getWriteSession(callback: GetWriteSessionCallback): void;
    /**
     * Retrieve a session.
     *
     * @param {GetSessionCallback} callback The callback function.
     */
    getSession(callback: GetSessionCallback): void;
    /**
     * Opens the pool, filling it to the configured number of read and write
     * sessions.
     *
     * @emits SessionPool#open
     * @return {Promise}
     */
    open(): void;
    /**
     * Releases session back into the pool.
     *
     * @throws {Error} For unknown sessions.
     * @emits SessionPool#available
     * @emits SessionPool#error
     * @fires SessionPool#session-available
     * @fires @deprecated SessionPool#readonly-available
     * @fires @deprecated SessionPool#readwrite-available
     * @param {Session} session The session to release.
     */
    release(session: Session): void;
    /**
     * Attempts to borrow a session from the pool.
     *
     * @private
     *
     * @returns {Promise<Session>}
     */
    _acquire(): Promise<Session>;
    /**
     * Moves a session into the borrowed group.
     *
     * @private
     *
     * @param {Session} session The session object.
     */
    _borrow(session: Session): void;
    /**
     * Borrows the first session from the inventory.
     *
     * @private
     *
     * @return {Session}
     */
    _borrowFrom(): Session;
    /**
     * Grabs the next available session.
     *
     * @private
     *
     * @returns {Promise<Session>}
     */
    _borrowNextAvailableSession(): Session;
    /**
     * Attempts to create a single session.
     *
     * @private
     *
     * @returns {Promise}
     */
    _createSession(): Promise<void>;
    /**
     * Batch creates sessions.
     *
     * @private
     *
     * @param {number} [amount] Config specifying how many sessions to create.
     * @returns {Promise}
     * @emits SessionPool#createError
     */
    _createSessions(amount: number): Promise<void>;
    /**
     * Attempts to delete a session, optionally creating a new one of the same
     * type if the pool is still open and we're under the configured min value.
     *
     * @private
     *
     * @fires SessionPool#error
     * @param {Session} session The session to delete.
     * @returns {Promise}
     */
    _destroy(session: Session): Promise<void>;
    /**
     * Deletes idle sessions that exceed the maxIdle configuration.
     *
     * @private
     */
    _evictIdleSessions(): void;
    /**
     * Fills the pool with the minimum number of sessions.
     *
     * @return {Promise}
     */
    _fill(): Promise<void>;
    /**
     * Retrieves a list of all the idle sessions.
     *
     * @private
     *
     * @returns {Session[]}
     */
    _getIdleSessions(): Session[];
    /**
     * Returns stack traces for sessions that have not been released.
     *
     * @return {string[]}
     */
    _getLeaks(): string[];
    /**
     * Returns true if the pool has a usable session.
     * @private
     */
    _hasSessionUsableFor(): boolean;
    /**
     * Attempts to get a session.
     *
     * @private
     *
     * @param {number} startTime Timestamp to use when determining timeouts.
     * @returns {Promise<Session>}
     */
    _getSession(startTime: number): Promise<Session>;
    /**
     * Checks to see whether or not session is expired.
     *
     * @param {Session} session The session to check.
     * @returns {boolean}
     */
    _isValidSession(session: Session): boolean;
    /**
     * Pings an individual session.
     *
     * @private
     *
     * @param {Session} session The session to ping.
     * @returns {Promise}
     */
    _ping(session: Session): Promise<void>;
    /**
     * Makes a keep alive request to all the idle sessions.
     *
     * @private
     *
     * @returns {Promise}
     */
    _pingIdleSessions(): Promise<void>;
    /**
     * Creates a transaction for a session.
     *
     * @private
     *
     * @param {Session} session The session object.
     * @param {object} options The transaction options.
     */
    _prepareTransaction(session: Session): void;
    /**
     * Releases a session back into the pool.
     *
     * @private
     *
     * @fires SessionPool#available
     * @fires SessionPool#session-available
     * @fires @deprecated SessionPool#readonly-available
     * @fires @deprecated SessionPool#readwrite-available
     * @param {Session} session The session object.
     */
    _release(session: Session): void;
    /**
     * Starts housekeeping (pinging/evicting) of idle sessions.
     *
     * @private
     */
    _startHouseKeeping(): void;
    /**
     * Stops housekeeping.
     *
     * @private
     */
    _stopHouseKeeping(): void;
}
export {};
