UNPKG

@itwin/core-backend

Version:
766 lines • 46 kB
/** @packageDocumentation * @module SQLiteDb */ import { AccessToken, Constructor, GuidString, OpenMode, Optional, PickAsyncMethods, PickMethods } from "@itwin/core-bentley"; import { LocalDirName, LocalFileName } from "@itwin/core-common"; import { BlobContainer } from "./BlobContainerService"; import type { SQLiteDb, VersionedSqliteDb } from "./SQLiteDb"; /** * Types for accessing SQLite databases stored in cloud containers. * @beta */ export declare namespace CloudSqlite { export type RequestTokenArgs = Optional<BlobContainer.RequestTokenProps, "userToken">; /** Add (or replace) a property to an object that is not enumerable. * This is important so this member will be skipped when the object is the target of * [structuredClone](https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) * (e.g. when the object is part of an exception that is marshalled across process boundaries.) */ export function addHiddenProperty<T>(o: T, p: PropertyKey, value?: any): T; export function getBlobService(): BlobContainer.ContainerService; /** * Request a new AccessToken for a cloud container using the [[BlobContainer]] service. * If the service is unavailable or returns an error, an empty token is returned. */ export function requestToken(args: RequestTokenArgs): Promise<AccessToken>; export function noLeadingOrTrailingSpaces(name: string, msg: string): void; export function validateDbName(dbName: DbName): void; /** * Create a new CloudContainer from a ContainerAccessProps. For non-public containers, a valid accessToken must be provided before the container * can be used (e.g. via [[CloudSqlite.requestToken]]). * @note After the container is successfully connected to a CloudCache, it will begin auto-refreshing its accessToken every `tokenRefreshSeconds` seconds (default is 1 hour) * until it is disconnected. However, if the container is public, or if `tokenRefreshSeconds` is <=0, auto-refresh is not enabled. */ export function createCloudContainer(args: ContainerAccessProps & { accessLevel?: BlobContainer.RequestAccessLevel; tokenFn?: (args: RequestTokenArgs) => Promise<AccessToken>; }): CloudContainer; /** Begin prefetching all blocks for a database in a CloudContainer in the background. */ export function startCloudPrefetch(container: CloudContainer, dbName: string, args?: PrefetchProps): CloudPrefetch; export interface ContainerProps { /** The type of storage provider. */ readonly storageType: "azure" | "google"; /** The base URI for the container. */ readonly baseUri: string; /** The name of the container. */ readonly containerId: string; /** true if the container is public (doesn't require authorization) */ readonly isPublic?: boolean; /** access token for container. If not present uses `CloudSqlite.requestToken` */ accessToken?: string; } /** Properties to access a CloudContainer. */ export interface ContainerAccessProps extends ContainerProps { /** an alias for the container. Defaults to `containerId` */ readonly alias?: string; /** SAS token that grants access to the container. */ accessToken: string; /** if true, container is allowed to request the write lock. */ readonly writeable?: boolean; /** if true, container is attached in "secure" mode (blocks are encrypted). Only supported in daemon mode. */ readonly secure?: boolean; /** string attached to log messages from CloudSQLite. This is most useful for identifying usage from daemon mode. */ readonly logId?: string; /** Duration for holding write lock, in seconds. After this time the write lock expires if not refreshed. Default is one hour. */ readonly lockExpireSeconds?: number; /** number of seconds between auto-refresh of access token. If <=0 no auto-refresh. Default is 1 hour (60*60) */ readonly tokenRefreshSeconds?: number; } /** Returned from `CloudContainer.queryDatabase` describing one database in the container */ export interface CachedDbProps { /** The total number of blocks in the database. */ readonly totalBlocks: number; /** the number of blocks of the database that have been downloaded into the CloudCache */ readonly localBlocks: number; /** the number of blocks from this database that have been modified in the CloudCache and need to be uploaded. */ readonly dirtyBlocks: number; /** If true, the database currently has transactions in the WAL file and may not be uploaded until they have been checkPointed. */ readonly transactions: boolean; /** the state of this database. Indicates whether the database is new or deleted since last upload */ readonly state: "" | "copied" | "deleted"; /** current number of clients that have this database open. */ readonly nClient: number; /** current number of ongoing prefetches on this database. */ readonly nPrefetch: number; } /** Filter options passed to CloudContainer.queryHttpLog * @internal */ export interface BcvHttpLogFilterOptions { /** only return rows whose ID is >= the provided id */ startFromId?: number; /** only return rows whose endTime is null OR >= the provided endTime. */ finishedAtOrAfterTime?: string; /** only return rows with a non-null end_time. */ showOnlyFinished?: boolean; } /** Returned from 'CloudContainer.queryHttpLog' describing a row in the bcv_http_log table. * @internal */ export interface BcvHttpLog { /** Unique, monotonically increasing id value */ readonly id: number; /** Time request was made, as iso-8601 */ readonly startTime: string; /** Time reply received, as iso-8601 (may be undefined) */ readonly endTime: string | undefined; /** "PUT", "GET", etc. */ readonly method: string; /** LogId of client that caused this request. Will be "prefetch" for prefetch requests. */ readonly logId: string; /** Log message associated with request */ readonly logmsg: string; /** URI of request */ readonly uri: string; /** HTTP response code (e.g. 200) */ readonly httpcode: number; } /** Filter options passed to 'CloudContainer.queryBcvStats' * @internal */ interface BcvStatsFilterOptions { /** if true, adds activeClients, totalClients, ongoingPrefetches, and attachedContainers to the result. */ addClientInformation?: boolean; } /** Returned from 'CloudContainer.queryBcvStats' describing the rows in the bcv_stat table. * Also gathers additional statistics using the other virtual tables bcv_container, bcv_database such as totalClients, ongoingPrefetches, activeClients and attachedContainers. * @internal */ export interface BcvStats { /** The total number of cache slots that are currently in use or 'locked' by ongoing client read transactions. In daemonless mode, this value is always 0. * A locked cache slot implies that it is not eligible for eviction in the event of a full cachefile. */ readonly lockedCacheslots: number; /** The current number of slots with data in them in the cache. */ readonly populatedCacheslots: number; /** The configured size of the cache, in number of slots. */ readonly totalCacheslots: number; /** The total number of clients opened on this cache */ readonly totalClients?: number; /** The total number of ongoing prefetches on this cache */ readonly ongoingPrefetches?: number; /** The total number of active clients on this cache. An active client is one which has an open read txn. */ readonly activeClients?: number; /** The total number of attached containers on this cache. */ readonly attachedContainers?: number; } /** The base name of a CloudSqlite database, without any version information. * The name must conform to the following constraints: * - Case-insensitively unique among all databases in the same [[CloudSqlite.CloudContainer]] * - Between 1 and 255 characters in length. * - A legal filename on both [Windows](https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions) and UNIX. * - Contain none of the following characters: forward or backward slash, period, single or double quote, backtick, colon, and "#". * - Begin or end with a whitespace character. * @see [[CloudSqlite.DbFullName]] for the fully-specified name, including version information. */ export type DbName = string; /** The fully-specified name of a CloudSqlite database, combining its [[CloudSqlite.DbName]] and [[CloudSqlite.DbVersion]] in the format "name:version". */ export type DbFullName = string; /** A [semver](https://github.com/npm/node-semver) string describing the version of a database, e.g., "4.2.11". */ export type DbVersion = string; /** A [semver string](https://github.com/npm/node-semver?tab=readme-ov-file#ranges) describing a range of acceptable versions, * e.g., ">=1.2.7 <1.3.0". */ export type DbVersionRange = string; /** Specifies the name and version of a CloudSqlite database. */ export interface DbNameAndVersion { /** The name of the database */ readonly dbName: DbName; /** The range of acceptable versions of the database of the specified [[dbName]]. * If omitted, it defaults to the newest available version. */ readonly version?: DbVersionRange; } export interface LoadProps extends DbNameAndVersion { readonly container: CloudContainer; /** If true, allow semver [prerelease versions](https://github.com/npm/node-semver?tab=readme-ov-file#prerelease-tags), e.g., "1.4.2-beta.0". * By default, only released version are allowed. */ readonly includePrerelease?: boolean; /** If true, start a prefetch operation whenever this database is opened, to begin downloading pages of the database before they are needed. */ readonly prefetch?: boolean; } /** * The release increment for a version number, used as part of [[CloudSqlite.CreateNewDbVersionArgs]] to specify the kind of version to create. * @see [semver.ReleaseType](https://www.npmjs.com/package/semver) */ export type SemverIncrement = "major" | "minor" | "patch" | "premajor" | "preminor" | "prepatch" | "prerelease"; /** * Arguments supplied to [[CloudSqlite.createNewDbVersion]]. */ export interface CreateNewDbVersionArgs { readonly fromDb: DbNameAndVersion; /** The type of version increment to apply to the source version. */ readonly versionType: SemverIncrement; /** For prerelease versions, a string that becomes part of the version name. */ readonly identifier?: string; } /** The name of a CloudSqlite database within a CloudContainer. */ export interface DbNameProp { /** the name of the database within the CloudContainer. * @note names of databases within a CloudContainer are always **case sensitive** on all platforms.*/ dbName: DbFullName; } export type TransferDirection = "upload" | "download"; export interface TransferProgress { /** a user-supplied progress function called during the transfer operation. Return a non-0 value to abort the transfer. */ onProgress?: (loaded: number, total: number) => number; } export interface CloudHttpProps { /** The number of simultaneous HTTP requests. Default is 6. */ nRequests?: number; } export interface PrefetchProps extends CloudHttpProps { /** timeout between requests, in milliseconds. Default is 100. */ timeout?: number; /** The number of prefetch requests to issue while there is foreground activity. Default is 3. */ minRequests?: number; } export interface TransferDbProps extends DbNameProp, TransferProgress, CloudHttpProps { /** the name of the local file to access the database for uploading and downloading */ localFileName: LocalFileName; } /** Properties for creating a CloudCache. */ export interface CacheProps extends CloudHttpProps { /** full path of directory for cache to store its files. Must be on a (preferably fast) local drive, and must be empty when the cache is first created. */ rootDir: string; /** name of this cache. It is possible to have more than one CloudCache in the same session, but each must have a unique name. */ name: string; /** maximum cache Size. Must be a number followed by either M (for megabytes) or G (for gigabytes.) Default is 1G */ cacheSize?: string; /** turn on diagnostics for `curl` (outputs to stderr) */ curlDiagnostics?: boolean; } /** Parameters used to obtain the write lock on a cloud container */ export interface ObtainLockParams { /** a string that identifies me to others if I hold the lock while they attempt to acquire it. */ user?: string; /** number of times to retry in the event the lock currently held by someone else. * After this number of attempts, `onFailure` is called. Default is 20. */ nRetries: number; /** Delay between retries, in milliseconds. Default is 100. */ retryDelayMs: number; /** function called if lock cannot be obtained after all retries. It is called with the name of the user currently holding the lock and * generally is expected that the user will be consulted whether to wait further. * If this function returns "stop", an exception will be thrown. Otherwise the retry cycle is restarted. */ onFailure?: WriteLockBusyHandler; } /** @internal */ export interface LockAndOpenArgs extends SQLiteDb.WithOpenDbArgs { /** a string that identifies me to others if I hold the lock while they attempt to acquire it. */ user: string; /** the name of the database within the container */ dbName: string; /** the CloudContainer on which the operation will be performed */ container: CloudContainer; /** if present, function called when the write lock is currently held by another user. */ busyHandler?: WriteLockBusyHandler; /** if present, open mode for Db. Default is ReadWrite */ openMode?: OpenMode; } /** Logging categories for `CloudCache.setLogMask` */ export enum LoggingMask { /** log all HTTP requests and responses */ HTTP = 1, /** log as blocks become dirty and must be uploaded */ DirtyBlocks = 2, /** log as blocks are added to the delete list */ AddToDelete = 4, /** log container lifecycle events (e.g. authorization requests, disconnects, and state transitions) */ LifecycleEvents = 8, /** Turn on all logging categories */ All = 255, /** Disable logging */ None = 0 } /** * A local cache for storing data downloaded from many CloudSqlite databases. This object refers to a directory on the local filesystem * and is used to **connect** CloudContainers so they may be accessed. It maintains the state of the local copy of * the downloaded data from SQLiteDbs in CloudContainers across sessions. * * Notes: * - CloudCaches have a name, used internally by CloudSqlite, that must be unique. CloudCaches are created and maintained via [[CloudCaches.getCache]]. * - All CloudContainers connected to a given CloudCache must have the same block size, as determined by the first CloudContainer connected. * - they have a maximum size that limits the amount of disk space they can consume. When the maximum size of a CloudCache is reached, * the least recently used blocks are removed to make room for new blocks. * - CloudCaches may only be used by a single process at a time. An exception is thrown if you attempt to access a CloudCache from a * second process if it is already in use by another process. Note: for a readonly CloudCache, a "daemon" process can be used to * share a CloudCache across processes. See its documentation for details. * - Generally, it is expected that there only be a few CloudCaches and they be shared by all applications. Each CloudCache can consume * its maximum disk space, so controlling system-wide disk usage is complicated. The only reason to make a new CloudCache is either * for containers with a different block size, or to purposely control local disk space usage for a specific set of containers. * - The contents of the cache directory are entirely controlled by CloudSqlite and should be empty when the cache is * first created and never modified directly thereafter. */ export interface CloudCache { /** `true` if this CloudCache is connected to a daemon process */ get isDaemon(): boolean; /** The name for this CloudCache. */ get name(): string; /** The root directory of this CloudCache on a local drive. */ get rootDir(): LocalDirName; /** A guid for this CloudCache. It is assigned when the CloudCache is first created and used for acquiring write locks. */ get guid(): GuidString; /** Configure logging for this CloudCache. * @param mask A bitmask of `LoggingMask` values * @note this method does nothing if [[isDaemon]] is true. Daemon logging is configured when the daemon is started. * @note HTTP logging can be happen on multiple threads and may be buffered. To see buffered log messages, periodically call * `[[IModelHost.flushLog]] */ setLogMask(mask: number): void; /** * destroy this CloudCache to end this session. All currently connected CloudContainers are disconnected first. * @note this does *not* delete the local directory. Its contents are maintained so it can be used in future sessions. * @note this function is automatically called on [[IModelHost.shutdown]], so it is only called directly for tests. * @internal */ destroy(): void; } export interface CleanDeletedBlocksOptions { /** * Any block that was marked as unused before this number of seconds ago will be deleted. Specifying a non-zero * value gives a period of time for other clients to refresh their manifests and stop using the now-garbage blocks. Otherwise they may get * a 404 error. Default is 1 hour. */ nSeconds?: number; /** if enabled, outputs verbose logs about the cleanup process. Output includes blocks determined eligible for deletion. * @default false */ debugLogging?: boolean; /** If true, iterates over all blobs in the cloud container to add blocks that are 'orphaned' to the delete list in the manifest. * Orphaned blocks are created when a client abruptly halts, is disconnected, or encounters an error while uploading a change. * If false, the search for 'orphaned' blocks is skipped and only any blocks which are already on the delete list are deleted. * @default true */ findOrphanedBlocks?: boolean; /** * a user-supplied progress function called during the cleanup operation. While the search for orphaned blocks occurs, nDeleted will be 0 and nTotalToDelete will be 1. * Once the search is complete and orphaned blocks begin being deleted, nDeleted will be the number of blocks deleted and nTotalToDelete will be the total number of blocks to delete. * If the return value is 1, the job will be cancelled and progress will be saved. If one or more blocks have already been deleted, then a new manifest file is uploaded saving the progress of the delete job. * Return any other non-0 value to cancel the job without saving progress. */ onProgress?: (nDeleted: number, nTotalToDelete: number) => Promise<number>; } /** * A CloudSqlite container that may be connected to a CloudCache. A CloudContainer maps a container in a cloud blob-storage * account to a local cache, so that the contents of a database in the container may be accessed as if it were a local file. * * Notes: * - all methods and accessors of this interface (other than `initializeContainer`) require that the `connect` method be successfully called first. * Otherwise they will throw an exception or return meaningless values. * - before a SQLiteDb in a container may be opened for write access, the container's write lock must be held (see [[acquireWriteLock]].) * - a single CloudContainer may hold more than one SQLiteDb, but often they are 1:1. * - the write lock is per-Container, not per-SQLiteDb (which is the reason they are often 1:1) * - the accessToken (a SAS key) member provides time limited, restricted, access to the container. It must be refreshed before it expires. * - when a CloudContainer is created, it may either be readonly or writeable. If a container is never meant to be used for writes, * it is slightly more efficient to indicate that by passing `writeable: false` */ export interface CloudContainer { onConnect?: (container: CloudContainer, cache: CloudCache) => void; onConnected?: (container: CloudContainer) => void; onDisconnect?: (container: CloudContainer, detach: boolean) => void; onDisconnected?: (container: CloudContainer, detach: boolean) => void; readonly cache?: CloudCache; /** the baseUri of this container */ get baseUri(): string; /** the storageType of this container */ get storageType(): string; /** The ContainerId within a storage account. */ get containerId(): string; /** The *alias* to identify this CloudContainer in a CloudCache. Usually just the ContainerId. */ get alias(): string; /** The logId. */ get logId(): string; /** The time that the write lock expires. Of the form 'YYYY-MM-DDTHH:MM:SS.000Z' in UTC. * Returns empty string if write lock is not held. */ get writeLockExpires(): string; /** true if this CloudContainer is currently connected to a CloudCache via the `connect` method. */ get isConnected(): boolean; /** true if this CloudContainer was created with the `writeable` flag (and its `accessToken` supplies write access). */ get isWriteable(): boolean; /** true if this container is public (doesn't require authorization ). */ get isPublic(): boolean; /** true if this CloudContainer currently holds the write lock for its container in the cloud. */ get hasWriteLock(): boolean; /** true if this CloudContainer has local changes that have not be uploaded to its container in the cloud. */ get hasLocalChanges(): boolean; /** The current accessToken providing access to the cloud container */ get accessToken(): string; set accessToken(val: string); /** Get the number of garbage blocks in this container that can be purged. */ get garbageBlocks(): number; /** The block size for this CloudContainer. */ get blockSize(): number; /** * initialize a cloud blob-store container to be used as a new CloudContainer. This creates the container's manifest of its contents, and should be * performed on an empty container. If an existing manifest is present, it is destroyed and a new one is created (essentially emptying the container.) */ initializeContainer(args: { checksumBlockNames?: boolean; blockSize: number; }): void; /** * Connect this CloudContainer to a CloudCache for accessing and/or modifying its contents. * @note A CloudCache is a local directory holding copies of information from the cloud. It is persistent across sessions, * but this method must be called each session to (re)establish the connection to the CloudCache. If the CloudCache was previously populated, * this method may be called and will succeed *even when offline* or without a valid `accessToken`. */ connect(cache: CloudCache): void; /** * Attempt to acquire the write lock for this CloudContainer. For this to succeed: * 1. it must be connected to a `CloudCache` * 2. this CloudContainer must have been constructed with `writeable: true` * 3. the `accessToken` must authorize write access * 4. no other process may be holding an unexpired write lock * @throws if any of the above conditions fail * @note Write locks *expire* after the duration specified in the `durationSeconds` property of the constructor argument, in case a process * crashes or otherwise fails to release the lock. Calling `acquireWriteLock` with the lock already held resets the lock duration from the current time, * so long running processes should call this method periodically to ensure their lock doesn't expire (they should also make sure their accessToken is refreshed * before it expires.) * @note on success, the container is synchronized with its contents in the cloud before the promise resolves. * @param user An identifier of the process/user locking the CloudContainer. In the event of a write lock * collision, this string will be included in the exception string of the *other* process attempting to obtain a write lock so that users may identify who currently holds * the lock. */ acquireWriteLock(user: string): void; /** * Release the write lock if it is currently held. * * Notes: * - if there are local changes that have not been uploaded, they are automatically uploaded before the write lock is released. * - if the write lock is not held, this method does nothing. */ releaseWriteLock(): void; /** * Destroy any currently valid write lock from this or any other process. This is obviously very dangerous and defeats the purpose of write locking. * This method exists only for administrator tools to clear a failed process without waiting for the expiration period. It can also be useful for tests. * For this to succeed, all of the conditions of `acquireWriteLock` must be true other than #4. */ clearWriteLock(): void; /** * Abandon any local changes in this container. If the write lock is currently held, it is released. * This function fails with BE_SQLITE_BUSY if there are any open read or write transactions on *any* database in the container. */ abandonChanges(): void; /** * Disconnect this CloudContainer from its CloudCache. There must be no open databases from this container. Leaves the container's contents in the * CloudCache so it is available for future sessions. * @note This function does nothing (and does not throw) if the CloudContainer is not connected to a CloudCache. */ disconnect(args?: { /** if true removes the container from the CloudCache, otherwise Leaves the container in the CloudCache so it is available for future sessions. */ detach?: boolean; }): void; /** * Poll cloud storage for changes from other processes. * * Notes: * - no changes made by other processes are visible to this CloudContainer unless/until this method is called. * - this is automatically called whenever the write lock is obtained to ensure all changes are against the latest version. * - any existing transactions on databases within the container will continue to use the old version of the manifest and therefore see no new changes pulled in. */ checkForChanges(): void; /** * Upload any changed blocks from the databases in this CloudContainer. * @note this is called automatically from `releaseWriteLock` before the write lock is released. It is only necessary to call this directly if you * wish to upload changes while the write lock is still held. * @see hasLocalChanges */ uploadChanges(): Promise<void>; /** * Create a copy of an existing database within this CloudContainer with a new name. * @note CloudSqlite uses copy-on-write semantics for this operation. That is, this method merely makes a * new entry in the manifest with the new name that *shares* all of its blocks with the original database. * If either database subsequently changes, the only modified blocks are not shared. */ copyDatabase(dbName: string, toAlias: string): Promise<void>; /** Remove a database from this CloudContainer. Unused blocks are moved to the delete list in the manifest. * @see [[CloudSqlite.cleanDeletedBlocks]] to actually delete the blocks from the delete list. */ deleteDatabase(dbName: string): Promise<void>; /** Get the list of database names in this CloudContainer. * @param globArg if present, filter the results with SQLite [GLOB](https://www.sqlite.org/lang_expr.html#glob) operator. */ queryDatabases(globArg?: string): string[]; /** * Get the status of a specific database in this CloudContainer. * @param dbName the name of the database of interest */ queryDatabase(dbName: string): CachedDbProps | undefined; /** * query the bcv_http_log table * @note the bcv_http_log table contains one row for each HTTP request made by the VFS or connected daemon. * @note Entries are automatically removed from the table on a FIFO basis. By default entries which are 1 hr old will be removed. * @internal */ queryHttpLog(filterOptions?: BcvHttpLogFilterOptions): CloudSqlite.BcvHttpLog[]; /** * query the bcv_stat table. * @internal */ queryBcvStats(filterOptions?: BcvStatsFilterOptions): CloudSqlite.BcvStats; /** * Get the SHA1 hash of the content of a database. * @param dbName the name of the database of interest * @note the hash will be empty if the database does not exist */ queryDatabaseHash(dbName: string): string; } /** * Object returned by [[CloudSqlite.startCloudPrefetch]]. * It holds a promise that is fulfilled when a Prefetch is completed. May also be used to cancel an in-progress prefetch. */ export interface CloudPrefetch { readonly cloudContainer: CloudContainer; readonly dbName: string; /** Cancel a currently pending prefetch. The promise will be resolved immediately after this call. */ cancel(): void; /** * Promise that is resolved when the prefetch completes or is cancelled. Await this promise to ensure that the * database has been fully downloaded before going offline, for example. * * Notes: * - resolves to `true` if the prefetch completed and the entire database is local, or `false` if it was aborted or failed. * - it is *not* rejected on `cancel`. Some progress may (or may not) have been made by the request. * - To monitor the progress being made during prefetch, call `CloudContainer.queryDatabase` periodically. */ promise: Promise<boolean>; } /** * Clean any unused deleted blocks from cloud storage. Unused deleted blocks can accumulate in cloud storage in a couple of ways: * 1) When a database is updated, a subset of its blocks are replaced by new versions, sometimes leaving the originals unused. * 2) A database is deleted with [[CloudContainer.deleteDatabase]] * In both cases, the blocks are not deleted immediately. Instead, they are scheduled for deletion at some later time. * Calling this method deletes all blocks in the cloud container for which the scheduled deletion time has passed. * @param container the CloudContainer to be cleaned. Must be connected and hold the write lock. * @param options options for the cleanup operation. @see CloudSqlite.CleanDeletedBlocksOptions */ export function cleanDeletedBlocks(container: CloudContainer, options: CleanDeletedBlocksOptions): Promise<void>; /** @internal */ export function transferDb(direction: TransferDirection, container: CloudContainer, props: TransferDbProps): Promise<void>; /** Upload a local SQLite database file into a CloudContainer. * @param container the CloudContainer holding the database. Must be connected. * @param props the properties that describe the database to be downloaded, plus optionally an `onProgress` function. * @note this function requires that the write lock be held on the container */ export function uploadDb(container: CloudContainer, props: TransferDbProps): Promise<void>; /** Download a database from a CloudContainer. * @param container the CloudContainer holding the database. Must be connected. * @param props the properties that describe the database to be downloaded, plus optionally an `onProgress` function. * @returns a Promise that is resolved when the download completes. * @note the download is "restartable." If the transfer is aborted and then re-requested, it will continue from where * it left off rather than re-downloading the entire file. */ export function downloadDb(container: CloudContainer, props: TransferDbProps): Promise<void>; /** Optional method to be called when an attempt to acquire the write lock fails because another user currently holds it. * @param lockedBy The identifier supplied by the application/user that currently holds the lock. * @param expires a stringified Date (in local time) indicating when the lock will expire. * @return "stop" to give up and stop retrying. Generally, it's a good idea to wait for some time before returning. */ export type WriteLockBusyHandler = (lockedBy: string, expires: string) => Promise<void | "stop">; /** * Attempt to acquire the write lock for a container, with retries. * If write lock is held by another user, call busyHandler if supplied. If no busyHandler, or handler returns "stop", throw. Otherwise try again. * @note if write lock is already held by the same user, this function will refresh the write lock's expiry time. * @param user the name to be displayed to other users in the event they attempt to obtain the lock while it is held by us * @param container the CloudContainer for which the lock is to be acquired * @param busyHandler if present, function called when the write lock is currently held by another user. * @throws if [[container]] is not connected to a CloudCache. */ export function acquireWriteLock(args: { user: string; container: CloudContainer; busyHandler?: WriteLockBusyHandler; }): Promise<void>; export function getWriteLockHeldBy(container: CloudContainer): string | undefined; /** release the write lock on a container. */ export function releaseWriteLock(container: CloudContainer): void; /** * Perform an asynchronous write operation on a CloudContainer with the write lock held. * 1. if write lock is already held by the current user, refresh write lock's expiry time, call operation and return. * 2. attempt to acquire the write lock, with retries. Throw if unable to obtain write lock. * 3. perform the operation * 3.a if the operation throws, abandon all changes and re-throw * 4. release the write lock. * 5. return value from operation * @param user the name to be displayed to other users in the event they attempt to obtain the lock while it is held by us * @param container the CloudContainer for which the lock is to be acquired * @param operation an asynchronous operation performed with the write lock held. * @param busyHandler if present, function called when the write lock is currently held by another user. * @returns a Promise with the result of `operation` */ export function withWriteLock<T>(args: { user: string; container: CloudContainer; busyHandler?: WriteLockBusyHandler; }, operation: () => Promise<T>): Promise<T>; /** * Parse the name of a Db stored in a CloudContainer into the dbName and version number. A single CloudContainer may hold * many versions of the same Db. The name of the Db in the CloudContainer is in the format "name:version". This * function splits them into separate strings. */ export function parseDbFileName(dbFileName: DbFullName): { dbName: DbName; version: DbVersion; }; export function validateDbVersion(version?: DbVersion): string; export function isSemverPrerelease(version: string): true | readonly (string | number)[] | null; export function isSemverEditable(dbFullName: string, container: CloudContainer): boolean | readonly (string | number)[]; /** Create a dbName for a database from its base name and version. This will be in the format "name:version" */ export function makeSemverName(dbName: DbName, version?: DbVersion): DbName; /** query the databases in the supplied container for the highest SemVer match according to the version range. Throws if no version available for the range. */ export function querySemverMatch(props: LoadProps): DbFullName; export function createNewDbVersion(container: CloudContainer, args: CreateNewDbVersionArgs): Promise<{ oldDb: DbNameAndVersion; newDb: DbNameAndVersion; }>; /** Arguments to create or find a CloudCache */ export interface CreateCloudCacheArg { /** The name of the CloudCache. CloudCache names must be unique. */ cacheName: string; /** A string that specifies the maximum size of the CloudCache. It should be a number followed by "K", * "M" "G", or "T". Default is "10G". */ cacheSize?: string; /** A local directory in temporary storage for the CloudCache. If not supplied, it is a subdirectory called `cacheName` * in the `CloudCaches` temporary directory. * If the directory does not exist, it is created. */ cacheDir?: string; } /** The collection of currently extant `CloudCache`s, by name. */ export class CloudCaches { private static readonly cloudCaches; /** create a new CloudCache */ private static makeCache; /** find a CloudCache by name, if it exists */ static findCache(cacheName: string): CloudCache | undefined; /** @internal */ static dropCache(cacheName: string): CloudCache | undefined; /** called by IModelHost after shutdown. * @internal */ static destroy(): void; /** Get a CloudCache by name. If the CloudCache doesn't yet exist, it is created. */ static getCache(args: CreateCloudCacheArg): CloudCache; } /** Class that provides convenient local access to a SQLite database in a CloudContainer. */ export class DbAccess<DbType extends VersionedSqliteDb, ReadMethods = DbType, WriteMethods = DbType> { /** The name of the database within the cloud container. */ readonly dbName: string; /** Parameters for obtaining the write lock for this container. */ readonly lockParams: ObtainLockParams; protected static _cacheName: string; protected _container: CloudContainer; protected _cloudDb: DbType; private _writeLockProxy?; private _readerProxy?; private get _ctor(); /** @internal */ static getCacheForClass(): CloudCache; private _cache?; /** only for tests * @internal */ setCache(cache: CloudCache): void; /** @internal */ getCache(): CloudCache; /** @internal */ getCloudDb(): DbType; /** * The token that grants access to the cloud container for this DbAccess. If it does not grant write permissions, all * write operations will fail. It should be refreshed (via a timer) before it expires. */ get sasToken(): AccessToken; set sasToken(token: AccessToken); /** the container for this DbAccess. It is automatically connected to the CloudCache whenever it is accessed. */ get container(): CloudContainer; /** Start a prefetch operation to download all the blocks for the VersionedSqliteDb */ startPrefetch(): CloudPrefetch; /** Create a new DbAccess for a database stored in a cloud container. */ constructor(args: { /** The Constructor for DbType. */ dbType: Constructor<DbType>; /** The properties of the cloud container holding the database. */ props: ContainerAccessProps; /** The name of the database within the container. */ dbName: string; }); /** Close the database for this DbAccess, if it is open */ closeDb(): void; /** Close the database for this DbAccess if it is opened, and disconnect this `DbAccess from its CloudContainer. */ close(): void; /** * Initialize a cloud container to hold VersionedSqliteDbs. The container must first be created by [[createBlobContainer]]. * This function creates and uploads an empty database into the container. * @note this deletes any existing content in the container. */ protected static _initializeDb(args: { dbType: typeof VersionedSqliteDb; props: ContainerProps; dbName: string; blockSize?: "64K" | "4M"; }): Promise<void>; /** * Create a new BlobContainer from the BlobContainer service to hold one or more VersionedSqliteDbs. * @returns A ContainerProps that describes the newly created container. * @note the current user must have administrator rights to create containers. */ protected static createBlobContainer(args: Omit<BlobContainer.CreateNewContainerProps, "userToken">): Promise<CloudSqlite.ContainerProps>; /** * Synchronize the local cache of this database with any changes by made by others. * @note This is called automatically whenever any write operation is performed on this DbAccess. It is only necessary to * call this directly if you have not changed the database recently, but wish to perform a readonly operation and want to * ensure it is up-to-date as of now. * @note There is no guarantee that the database is up-to-date even immediately after calling this method, since others * may be modifying it at any time. */ synchronizeWithCloud(): void; /** * Ensure that the database controlled by this `DbAccess` is open for read access and return the database object. * @note if the database is already open (either for read or write), this method merely returns the database object. */ openForRead(): DbType; /** * Perform an operation on this database with the lock held and the database opened for write * @param operationName the name of the operation. Only used for logging. * @param operation a function called with the lock held and the database open for write. * @returns A promise that resolves to the the return value of `operation`. * @see `SQLiteDb.withLockedContainer` * @note Most uses of `CloudSqliteDbAccess` require that the lock not be held by any operation for long. Make sure you don't * do any avoidable or time consuming work in your operation function. */ withLockedDb<T>(args: { operationName: string; openMode?: OpenMode; user?: string; }, operation: () => Promise<T>): Promise<T>; /** get a method member, by name, from the database object. Throws if not a Function. */ private getDbMethod; /** * A Proxy Object to call a writeable async method on the cloud database controlled by this `DbAccess`. * * Whenever a method is called through this Proxy, it will: * - attempt to acquire the write lock on the container * - open the database for write * - call the method * - close the database * - upload changes * - release the write lock. * * @see [[withLockedDb]] */ get writeLocker(): PickAsyncMethods<WriteMethods>; /** * A Proxy Object to call a synchronous readonly method on the database controlled by this `DbAccess`. * Whenever a method is called through this Proxy, it will first ensure that the database is opened for at least read access. */ get reader(): PickMethods<ReadMethods>; } export {}; } //# sourceMappingURL=CloudSqlite.d.ts.map