diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index b5602037615..0f657aadff7 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -912,6 +912,10 @@ export interface FeatureToggles { */ unifiedStorageGrpcConnectionPool?: boolean; /** + * Use KV-backed SQL storage backend instead of direct SQL queries + */ + unifiedStorageKVBackend?: boolean; + /** * Enables UI functionality to permanently delete alert rules * @default true */ diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 8ecc3a481e7..f6fb0591dfc 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1580,6 +1580,14 @@ var ( HideFromAdminPage: true, HideFromDocs: true, }, + { + Name: "unifiedStorageKVBackend", + Description: "Use KV-backed SQL storage backend instead of direct SQL queries", + Stage: FeatureStageExperimental, + Owner: grafanaSearchAndStorageSquad, + HideFromAdminPage: true, + HideFromDocs: true, + }, { Name: "alertingRulePermanentlyDelete", Description: "Enables UI functionality to permanently delete alert rules", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index bba9ab351d2..66c7ea7d656 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -205,6 +205,7 @@ unifiedStorageHistoryPruner,GA,@grafana/search-and-storage,false,false,false azureMonitorLogsBuilderEditor,preview,@grafana/partner-datasources,false,false,false localeFormatPreference,preview,@grafana/grafana-frontend-platform,false,false,false unifiedStorageGrpcConnectionPool,experimental,@grafana/search-and-storage,false,false,false +unifiedStorageKVBackend,experimental,@grafana/search-and-storage,false,false,false alertingRulePermanentlyDelete,GA,@grafana/alerting-squad,false,false,true alertingRuleRecoverDeleted,GA,@grafana/alerting-squad,false,false,true multiTenantTempCredentials,experimental,@grafana/aws-datasources,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 1f5f7b42489..f87d46a3b45 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -830,6 +830,10 @@ const ( // Enables the unified storage grpc connection pool FlagUnifiedStorageGrpcConnectionPool = "unifiedStorageGrpcConnectionPool" + // FlagUnifiedStorageKVBackend + // Use KV-backed SQL storage backend instead of direct SQL queries + FlagUnifiedStorageKVBackend = "unifiedStorageKVBackend" + // FlagAlertingRulePermanentlyDelete // Enables UI functionality to permanently delete alert rules FlagAlertingRulePermanentlyDelete = "alertingRulePermanentlyDelete" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 852e0e7f3b3..81512202e1a 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -4208,6 +4208,20 @@ "expression": "true" } }, + { + "metadata": { + "name": "unifiedStorageKVBackend", + "resourceVersion": "1763461706359", + "creationTimestamp": "2025-11-18T10:28:26Z" + }, + "spec": { + "description": "Use KV-backed SQL storage backend instead of direct SQL queries", + "stage": "experimental", + "codeowner": "@grafana/search-and-storage", + "hideFromAdminPage": true, + "hideFromDocs": true + } + }, { "metadata": { "name": "unifiedStorageSearch", diff --git a/pkg/storage/unified/sql/server.go b/pkg/storage/unified/sql/server.go index 60fa9b8467a..97a82dd8dad 100644 --- a/pkg/storage/unified/sql/server.go +++ b/pkg/storage/unified/sql/server.go @@ -101,21 +101,46 @@ func NewResourceServer(opts ServerOptions) (resource.ResourceServer, error) { //nolint:staticcheck // not yet migrated to OpenFeature withPruner := opts.Features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageHistoryPruner) - backend, err := NewBackend(BackendOptions{ - DBProvider: eDB, - Tracer: opts.Tracer, - Reg: opts.Reg, - IsHA: isHA, - withPruner: withPruner, - storageMetrics: opts.StorageMetrics, - LastImportTimeMaxAge: opts.SearchOptions.MaxIndexAge, // No need to keep last_import_times older than max index age. - }) - if err != nil { - return nil, err + // Check if KV backend is enabled via feature flag + //nolint:staticcheck // not yet migrated to OpenFeature + if opts.Features.IsEnabledGlobally(featuremgmt.FlagUnifiedStorageKVBackend) { + // Create SQL KV instance + sqlKV, err := resource.NewSQLKV(eDB) + if err != nil { + return nil, fmt.Errorf("create SQL KV: %w", err) + } + + // Use existing KV storage backend (already implements StorageBackend interface) + kvBackend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ + KvStore: sqlKV, + WithPruner: withPruner, + Tracer: opts.Tracer, + Reg: opts.Reg, + }) + if err != nil { + return nil, fmt.Errorf("create KV backend: %w", err) + } + serverOptions.Backend = kvBackend + // Note: kvStorageBackend doesn't implement Diagnostics/Lifecycle yet + // For now, we'll leave these nil and they will be handled by the server + } else { + // Use existing SQL backend + backend, err := NewBackend(BackendOptions{ + DBProvider: eDB, + Tracer: opts.Tracer, + Reg: opts.Reg, + IsHA: isHA, + withPruner: withPruner, + storageMetrics: opts.StorageMetrics, + LastImportTimeMaxAge: opts.SearchOptions.MaxIndexAge, // No need to keep last_import_times older than max index age. + }) + if err != nil { + return nil, err + } + serverOptions.Backend = backend + serverOptions.Diagnostics = backend + serverOptions.Lifecycle = backend } - serverOptions.Backend = backend - serverOptions.Diagnostics = backend - serverOptions.Lifecycle = backend } serverOptions.Search = opts.SearchOptions