<commit_before>import * as uuid from "uuid";
import * as BluebirdPromise from "bluebird";

import { throwError } from "../Exceptions";
import { RequestExecutor } from "../Http/RequestExecutor";
import { getLogger } from "../Utility/LogUtil";
import { DocumentStoreBase } from "./DocumentStoreBase";
import { IDocumentStore } from "./IDocumentStore";
import { MaintenanceOperationExecutor } from "./Operations/MaintenanceOperationExecutor";
import { OperationExecutor } from "./Operations/OperationExecutor";
import { IDocumentSession, ISessionOptions } from "./Session/IDocumentSession";
import { DocumentSession } from "./Session/DocumentSession";
import { HiloMultiDatabaseIdGenerator } from "./Identity/HiloMultiDatabaseIdGenerator";
import { IAuthOptions } from "../Auth/AuthOptions";
import { BulkInsertOperation } from "./BulkInsertOperation";
import { IDatabaseChanges } from "./Changes/IDatabaseChanges";
import { DatabaseChanges } from "./Changes/DatabaseChanges";

const log = getLogger({ module: "DocumentStore" });

export class DocumentStore extends DocumentStoreBase {

    private _log =
        getLogger({ module: "DocumentStore-" + Math.floor(Math.random() * 1000) });

    private readonly _databaseChanges: Map<string, IDatabaseChanges> = new Map();
    // TBD: private ConcurrentDictionary<string, Lazy<EvictItemsFromCacheBasedOnChanges>> _aggressiveCacheChanges =
    // new ConcurrentDictionary<string, Lazy<EvictItemsFromCacheBasedOnChanges>>();
    // TBD: private readonly ConcurrentDictionary<string, EvictItemsFromCacheBasedOnChanges> 
    // _observeChangesAndEvictItemsFromCacheForDatabases = 
    // new ConcurrentDictionary<string, EvictItemsFromCacheBasedOnChanges>();

    private _requestExecutors: Map<string, RequestExecutor> = new Map();

    private _multiDbHiLo: HiloMultiDatabaseIdGenerator;

    private _maintenanceOperationExecutor: MaintenanceOperationExecutor;
    private _operationExecutor: OperationExecutor;

    private _identifier: string;
    private _aggressiveCachingUsed: boolean;

    public constructor(url: string, database: string);
    public constructor(urls: string[], database: string);
    public constructor(url: string, database: string, authOptions: IAuthOptions);
    public constructor(urls: string[], database: string, authOptions: IAuthOptions);
    public constructor(urls: string | string[], database: string, authOptions?: IAuthOptions) {
        super();

        this._database = database;
        this.authOptions = authOptions;
        this.urls = Array.isArray(urls)
            ? urls as string[]
            : [urls];
    }

    public get identifier(): string {
        if (this._identifier) {
            return this._identifier;
        }

        if (!this._urls) {
            return null;
        }

        const urlsString = this._urls.join(", ");
        if (this._database) {
            return `${ urlsString } DB: ${this._database}`;
        }

        return urlsString;
    }

    public set identifier(identifier: string) {
        this._identifier = identifier;
    }

    /**
     * Disposes the document store
     */
    public dispose(): void {
        this._log.info("Dispose.");
        this.emit("beforeDispose");

        /* TBD
            foreach (var value in _aggressiveCacheChanges.Values)
            {
                if (value.IsValueCreated == false)
                    continue;

                value.Value.Dispose();
            }*/
        this._databaseChanges.forEach(change => change.dispose());

        /* TODO
            // try to wait until all the async disposables are completed
            Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(3));
            // if this is still going, we continue with disposal, it is for graceful shutdown only, anyway
        */

        const disposeChain = BluebirdPromise.resolve();

        disposeChain
            .then(() => {
                if (this._multiDbHiLo) {
                    return Promise.resolve()
                        .then(() => this._multiDbHiLo.returnUnusedRange())
                        .catch(err => this._log.warn("Error returning unused ID range.", err));
                }
            })
            .then(() => {
                this._disposed = true;
                // TBD: Subscriptions?.Dispose();

                return new BluebirdPromise((resolve, reject) => {
                    let listenersExecCallbacksCount = 0;
                    const listenersCount = this.listenerCount("afterDispose");
                    
                    this.emit("afterDispose", () => {
                        if (listenersCount === ++listenersExecCallbacksCount) {
                            resolve();
                        }
                    });

                })
                    .timeout(5000)
                    .catch((err) => this._log.warn(`Error handling 'afterDispose'`, err));
            })
            .then(() => {<commit_msg>fix doc store dispose timeout<commit_after>import * as uuid from "uuid";
import * as BluebirdPromise from "bluebird";

import { throwError } from "../Exceptions";
import { RequestExecutor } from "../Http/RequestExecutor";
import { getLogger } from "../Utility/LogUtil";
import { DocumentStoreBase } from "./DocumentStoreBase";
import { IDocumentStore } from "./IDocumentStore";
import { MaintenanceOperationExecutor } from "./Operations/MaintenanceOperationExecutor";
import { OperationExecutor } from "./Operations/OperationExecutor";
import { IDocumentSession, ISessionOptions } from "./Session/IDocumentSession";
import { DocumentSession } from "./Session/DocumentSession";
import { HiloMultiDatabaseIdGenerator } from "./Identity/HiloMultiDatabaseIdGenerator";
import { IAuthOptions } from "../Auth/AuthOptions";
import { BulkInsertOperation } from "./BulkInsertOperation";
import { IDatabaseChanges } from "./Changes/IDatabaseChanges";
import { DatabaseChanges } from "./Changes/DatabaseChanges";

const log = getLogger({ module: "DocumentStore" });

export class DocumentStore extends DocumentStoreBase {

    private _log =
        getLogger({ module: "DocumentStore-" + Math.floor(Math.random() * 1000) });

    private readonly _databaseChanges: Map<string, IDatabaseChanges> = new Map();
    // TBD: private ConcurrentDictionary<string, Lazy<EvictItemsFromCacheBasedOnChanges>> _aggressiveCacheChanges =
    // new ConcurrentDictionary<string, Lazy<EvictItemsFromCacheBasedOnChanges>>();
    // TBD: private readonly ConcurrentDictionary<string, EvictItemsFromCacheBasedOnChanges> 
    // _observeChangesAndEvictItemsFromCacheForDatabases = 
    // new ConcurrentDictionary<string, EvictItemsFromCacheBasedOnChanges>();

    private _requestExecutors: Map<string, RequestExecutor> = new Map();

    private _multiDbHiLo: HiloMultiDatabaseIdGenerator;

    private _maintenanceOperationExecutor: MaintenanceOperationExecutor;
    private _operationExecutor: OperationExecutor;

    private _identifier: string;
    private _aggressiveCachingUsed: boolean;

    public constructor(url: string, database: string);
    public constructor(urls: string[], database: string);
    public constructor(url: string, database: string, authOptions: IAuthOptions);
    public constructor(urls: string[], database: string, authOptions: IAuthOptions);
    public constructor(urls: string | string[], database: string, authOptions?: IAuthOptions) {
        super();

        this._database = database;
        this.authOptions = authOptions;
        this.urls = Array.isArray(urls)
            ? urls as string[]
            : [urls];
    }

    public get identifier(): string {
        if (this._identifier) {
            return this._identifier;
        }

        if (!this._urls) {
            return null;
        }

        const urlsString = this._urls.join(", ");
        if (this._database) {
            return `${ urlsString } DB: ${this._database}`;
        }

        return urlsString;
    }

    public set identifier(identifier: string) {
        this._identifier = identifier;
    }

    /**
     * Disposes the document store
     */
    public dispose(): void {
        this._log.info("Dispose.");
        this.emit("beforeDispose");

        /* TBD
            foreach (var value in _aggressiveCacheChanges.Values)
            {
                if (value.IsValueCreated == false)
                    continue;

                value.Value.Dispose();
            }*/
        this._databaseChanges.forEach(change => change.dispose());

        /* TODO
            // try to wait until all the async disposables are completed
            Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(3));
            // if this is still going, we continue with disposal, it is for graceful shutdown only, anyway
        */

        const disposeChain = BluebirdPromise.resolve();

        disposeChain
            .then(() => {
                if (this._multiDbHiLo) {
                    return Promise.resolve()
                        .then(() => this._multiDbHiLo.returnUnusedRange())
                        .catch(err => this._log.warn("Error returning unused ID range.", err));
                }
            })
            .then(() => {
                this._disposed = true;
                // TBD: Subscriptions?.Dispose();

                return new BluebirdPromise((resolve, reject) => {
                    let listenersExecCallbacksCount = 0;
                    const listenersCount = this.listenerCount("afterDispose");
                    if (listenersCount === 0) {
                        resolve();
                    } else {
                        this.emit("afterDispose", () => {
                            if (listenersCount === ++listenersExecCallbacksCount) {
                                resolve();
                            }
                        });
                    }
                })
                .timeout(5000)
                .catch((err) => this._log.warn(`Error handling 'afterDispose'`, err));
            })
            .then(() => {
{'fraction_non_alphanumeric': 0.1099601593625498, 'fraction_numerical': 0.0020916334661354582, 'mean_word_length': 2.3436563436563436, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7564552', 'n_tokens_mistral': 2507, 'n_tokens_neox': 2415, 'n_words': 603}