Skip to content

Commit

Permalink
Problem: could not aggregate event-level data in a stats manager, bad…
Browse files Browse the repository at this point in the history
… wording of stats classes

Solution: add tickStats as an event-level aggregator without TimeFrames and integrate with accountTimeSeries.ts; rename timeSeries.ts to timeFrameStats.ts and related classes; also add docs
  • Loading branch information
MHHukiewitz committed Jan 28, 2023
1 parent ff41b33 commit 3d4eeee
Show file tree
Hide file tree
Showing 17 changed files with 9,645 additions and 619 deletions.
9,507 changes: 9,170 additions & 337 deletions package-lock.json

Large diffs are not rendered by default.

25 changes: 13 additions & 12 deletions packages/framework/src/utils/domain/indexer/main.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { Utils } from '@aleph-indexer/core'
import { TransactionRequest } from '../../../services/indexer/src/dal/transactionRequest.js'
import { Utils } from "@aleph-indexer/core";
import { TransactionRequest } from "../../../services/indexer/src/dal/transactionRequest.js";
import {
AccountIndexerRequestArgs,
AccountIndexerState,
GetTransactionPendingRequestsRequestArgs,
IndexerMainDomainContext,
} from '../../../services/indexer/src/types.js'
import { Blockchain } from '../../../types.js'
import {
AccountTimeSeriesStats,
AccountStatsFilters,
AccountStats,
} from '../../stats/types.js'
IndexerMainDomainContext
} from "../../../services/indexer/src/types.js";
import { Blockchain } from "../../../types.js";
import { AccountStats, AccountTimeSeriesStats, TimeSeriesStatsFilters } from "../../stats/types.js";

/**
* Describes the main indexer domain class capable of calculating stats.
Expand All @@ -24,6 +20,7 @@ export type IndexerMainDomainWithStats = {
updateStats(now: number): Promise<void>
/**
* Returns the time-series stats for the given account.
* @param blockchainId The blockchain to get the time-series stats from.
* @param accounts The accounts to get the time-series stats from.
* @param type The type of time-series to get.
* @param filters The transformations and clipping to apply to the time-series.
Expand All @@ -32,10 +29,11 @@ export type IndexerMainDomainWithStats = {
blockchainId: Blockchain,
accounts: string[],
type: string,
filters: AccountStatsFilters,
filters: TimeSeriesStatsFilters
): Promise<AccountTimeSeriesStats[]>
/**
* Returns the global stats for the given accounts.
* @param blockchainId The blockchain to get the summary from.
* @param accounts The accounts to get the summary from.
*/
getAccountStats(
Expand Down Expand Up @@ -146,6 +144,7 @@ export abstract class IndexerMainDomain {

/**
* Gets the indexing state of the given accounts.
* @param blockchainId The blockchain to get the state from.
* @param accounts The accounts to get the state from.
*/
async getAccountState(
Expand All @@ -165,6 +164,7 @@ export abstract class IndexerMainDomain {

/**
* Returns the time-series stats for the given account.
* @param blockchainId The blockchain to get the time-series stats from.
* @param accounts The accounts to get the time-series stats from.
* @param type The type of time-series to get.
* @param filters The transformations and clipping to apply to the time-series.
Expand All @@ -173,7 +173,7 @@ export abstract class IndexerMainDomain {
blockchainId: Blockchain,
accounts: string[] = [],
type: string,
filters: AccountStatsFilters,
filters: TimeSeriesStatsFilters
): Promise<AccountTimeSeriesStats<V>[]> {
this.checkStats()

Expand All @@ -196,6 +196,7 @@ export abstract class IndexerMainDomain {

/**
* Returns the global stats for the given accounts.
* @param blockchainId The blockchain to get the summary from.
* @param accounts The accounts to get the summary from.
*/
async getAccountStats<V>(
Expand Down
18 changes: 7 additions & 11 deletions packages/framework/src/utils/domain/indexer/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@ import {
AccountIndexerRequestArgs,
IndexerDomainContext,
IndexerWorkerDomainI,
TransactionDateRangeResponse,
} from '../../../services/indexer/src/types.js'
import { Blockchain, ParsedTransaction } from '../../../types.js'
import {
AccountTimeSeriesStats,
AccountStatsFilters,
AccountStats,
} from '../../stats/index.js'
import { WorkerKind } from '../../workers.js'
import { importBlockchainWorkerIndexerDomain } from '../common.js'
TransactionDateRangeResponse
} from "../../../services/indexer/src/types.js";
import { Blockchain, ParsedTransaction } from "../../../types.js";
import { AccountStats, AccountTimeSeriesStats, TimeSeriesStatsFilters } from "../../stats/index.js";
import { WorkerKind } from "../../workers.js";
import { importBlockchainWorkerIndexerDomain } from "../common.js";

/**
* Describes an indexer worker domain, capable of stats processing.
Expand All @@ -21,7 +17,7 @@ export type IndexerWorkerDomainWithStats = {
getTimeSeriesStats(
account: string,
type: string,
filters: AccountStatsFilters,
filters: TimeSeriesStatsFilters
): Promise<AccountTimeSeriesStats>
getStats(account: string): Promise<AccountStats>
}
Expand Down
63 changes: 27 additions & 36 deletions packages/framework/src/utils/stats/accountTimeSeries.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,29 @@
import { Utils } from '@aleph-indexer/core'
import { IndexerMsClient } from '../../services/indexer/index.js'
import { Utils } from "@aleph-indexer/core";
import { IndexerMsClient } from "../../services/indexer/index.js";
import { DateRange, getDateRangeFromInterval, mergeDateRangesFromIterable, TimeFrame } from "../time.js";
import {
DateRange,
getDateRangeFromInterval,
mergeDateRangesFromIterable,
} from '../time.js'
import {
StatsStateStorage,
StatsStateState,
StatsStateDALIndex,
StatsState,
} from './dal/statsState.js'
import { StatsTimeSeriesStorage } from './dal/statsTimeSeries.js'
import {
AccountTimeSeriesStats,
AccountStatsFilters,
AccountTimeSeriesStatsConfig,
AccountStats,
} from './types.js'
TimeFrameState,
TimeFrameStateCode,
TimeFrameStateDALIndex,
TimeFrameStateStorage
} from "./dal/timeFrameState.js";
import { TimeFrameStatsStorage } from "./dal/timeFrameEntity.js";
import { AccountStats, AccountTimeSeriesStats, AccountTimeSeriesStatsConfig, TimeSeriesStatsFilters } from "./types.js";

const { JobRunner } = Utils
const { JobRunner } = Utils;

/**
* Defines the account stats handler class.
*/
export class AccountTimeSeriesStatsManager<V> {
protected compactionJob!: Utils.JobRunner
protected stats!: AccountStats<V>
protected compactionJob!: Utils.JobRunner;
protected stats!: AccountStats<V>;

constructor(
public config: AccountTimeSeriesStatsConfig<V>,
protected indexerClient: IndexerMsClient,
protected stateDAL: StatsStateStorage,
protected timeSeriesDAL: StatsTimeSeriesStorage,
protected stateDAL: TimeFrameStateStorage,
protected timeSeriesDAL: TimeFrameStatsStorage
) {
this.compactionJob = new JobRunner({
name: `stats-compactor ${config.account}`,
Expand All @@ -49,7 +40,7 @@ export class AccountTimeSeriesStatsManager<V> {

async getTimeSeriesStats(
type: string,
filters: AccountStatsFilters,
filters: TimeSeriesStatsFilters
): Promise<AccountTimeSeriesStats> {
const { account } = this.config

Expand All @@ -60,8 +51,8 @@ export class AccountTimeSeriesStatsManager<V> {
if (!timeSeries)
throw new Error(`Stats for ${account} of type "${type}" not found`)

const series = await timeSeries.getStats(account, filters)
const { timeFrame } = filters
const series = await timeSeries.getStats(account, filters);
const timeFrame = filters.timeFrame ?? TimeFrame.Tick;

return {
account,
Expand Down Expand Up @@ -136,28 +127,28 @@ export class AccountTimeSeriesStatsManager<V> {
}

protected async compactStates(): Promise<void> {
const { account } = this.config
const { Processed } = StatsStateState
const { account } = this.config;
const { Processed } = TimeFrameStateCode;

const fetchedRanges = await this.stateDAL
.useIndex(StatsStateDALIndex.AccountTypeState)
.useIndex(TimeFrameStateDALIndex.AccountTypeState)
.getAllValuesFromTo([account, Processed], [account, Processed], {
reverse: false,
})
reverse: false
});

const { newRanges, oldRanges } = await mergeDateRangesFromIterable(
fetchedRanges,
)
fetchedRanges
);

const newStates = newRanges.map((range) => {
const newState = range as StatsState
const newState = range as TimeFrameState;
newState.account = account
newState.state = Processed
return newState
})

const oldStates = oldRanges.map((range) => {
const oldState = range as StatsState
const oldState = range as TimeFrameState;
oldState.account = account
oldState.state = Processed
return oldState
Expand Down
4 changes: 2 additions & 2 deletions packages/framework/src/utils/stats/dal/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './statsState.js'
export * from './statsTimeSeries.js'
export * from "./timeFrameState.js";
export * from "./timeFrameEntity.js";
68 changes: 0 additions & 68 deletions packages/framework/src/utils/stats/dal/statsState.ts

This file was deleted.

48 changes: 0 additions & 48 deletions packages/framework/src/utils/stats/dal/statsTimeSeries.ts

This file was deleted.

33 changes: 33 additions & 0 deletions packages/framework/src/utils/stats/dal/tickEntity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { EntityStorage } from "@aleph-indexer/core";

export type TickEntity<T> = {
account: string
type: string
date: number
data: T
}

export type TickStatsStorage = EntityStorage<TickEntity<any>>

const accountKey = {
get: (e: TickEntity<unknown>) => e.account,
length: EntityStorage.AddressLength
};

const typeKey = {
get: (e: TickEntity<unknown>) => e.type,
length: EntityStorage.VariableLength
};

const dateKey = {
get: (e: TickEntity<unknown>) => e.date,
length: EntityStorage.TimestampLength
};

export function createStatsTimeSeriesDAL(path: string): TickStatsStorage {
return new EntityStorage<TickEntity<any>>({
name: "stats_time_series",
path,
key: [accountKey, typeKey, dateKey]
});
}
Loading

0 comments on commit 3d4eeee

Please sign in to comment.