Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,993 changes: 1,503 additions & 1,490 deletions proto/gen/rill/runtime/v1/api.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions proto/gen/rill/runtime/v1/api.pb.validate.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions proto/gen/rill/runtime/v1/runtime.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5435,6 +5435,12 @@ definitions:
properties:
instance:
$ref: '#/definitions/v1Instance'
dataSizeBytes:
type: string
format: int64
description: |-
data_size_bytes is the total size of the instance's data directory in bytes.
This is the same value reported to billing/Orb as "data_dir_size_bytes".
title: Response message for RuntimeService.GetInstance
v1GetLogsResponse:
type: object
Expand Down
3 changes: 3 additions & 0 deletions proto/rill/runtime/v1/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ message GetInstanceRequest {
// Response message for RuntimeService.GetInstance
message GetInstanceResponse {
Instance instance = 1;
// data_size_bytes is the total size of the instance's data directory in bytes.
// This is the same value reported to billing/Orb as "data_dir_size_bytes".
int64 data_size_bytes = 2;
}

// Request message for RuntimeService.CreateInstance.
Expand Down
10 changes: 10 additions & 0 deletions runtime/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ func (r *Runtime) DataDir(instanceID string, elem ...string) (string, error) {
return r.storage.WithPrefix(instanceID).DataDir(elem...)
}

// DataDirSize returns the total size of the instance's data directory in bytes.
// This is the same value reported to billing/Orb as "data_dir_size_bytes".
func (r *Runtime) DataDirSize(instanceID string) (int64, error) {
dataDir, err := r.storage.WithPrefix(instanceID).DataDir()
if err != nil {
return 0, err
}
return sizeOfDir(dataDir), nil
}

// TempDir returns the path to a temporary directory for the given instance. The directory is created if it doesn't exist.
// The TempDir is a fixed location. The caller is responsible for cleaning up after use.
// The TempDir may be cleared after restarts.
Expand Down
14 changes: 12 additions & 2 deletions runtime/server/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,19 @@ func (s *Server) GetInstance(ctx context.Context, req *runtimev1.GetInstanceRequ
return nil, status.Error(codes.InvalidArgument, err.Error())
}

return &runtimev1.GetInstanceResponse{
resp := &runtimev1.GetInstanceResponse{
Instance: instanceToPB(inst, featureFlags, req.Sensitive),
}, nil
}

// Compute data dir size (best-effort; don't fail the request if it errors)
if sensitiveAccess {
size, err := s.runtime.DataDirSize(req.InstanceId)
if err == nil {
resp.DataSizeBytes = size
}
}

return resp, nil
}

// CreateInstance implements RuntimeService.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<script lang="ts">
import { page } from "$app/stores";
import {
createAdminServiceGetProject,
V1DeploymentStatus,
} from "@rilldata/web-admin/client";
import { useDashboardsLastUpdated } from "@rilldata/web-admin/features/dashboards/listing/selectors";
import { useGithubLastSynced } from "@rilldata/web-admin/features/projects/selectors";
import { isTeamPlan } from "@rilldata/web-admin/features/billing/plans/utils";
import { createRuntimeServiceGetInstance } from "@rilldata/web-common/runtime-client";
import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2";
import { formatMemorySize } from "@rilldata/web-common/lib/number-formatting/memory-size";
import { useProjectDeployment, useRuntimeVersion } from "../selectors";
import {
formatEnvironmentName,
Expand Down Expand Up @@ -52,6 +55,21 @@
sensitive: true,
});
$: instance = $instanceQuery.data?.instance;
$: dataSizeBytes = $instanceQuery.data?.dataSizeBytes;

// Plan-based storage cap (from root layout data)
const TEAM_STORAGE_CAP = 10 * 1024 * 1024 * 1024; // 10GB
$: planName = $page.data?.organization?.billingPlanName ?? "";
$: storageCap = isTeamPlan(planName) ? TEAM_STORAGE_CAP : 0;

// Fill percentage for the usage pill (0–100)
$: usagePercent = (() => {
const bytes = Number(dataSizeBytes ?? 0);
if (!storageCap) return bytes > 0 ? 100 : 0;
return Math.min(Math.round((bytes / storageCap) * 100), 100);
})();
$: isOverCap = storageCap > 0 && Number(dataSizeBytes ?? 0) >= storageCap;

// Repo — only shown when the user connected their own GitHub
$: githubUrl = projectData?.gitRemote
? getGitUrlFromRemote(projectData.gitRemote)
Expand Down Expand Up @@ -155,6 +173,34 @@
{/if}
</span>
</div>

{#if !olapConnector || olapConnector.provision}
<div class="info-row">
<span class="info-label">Data usage</span>
<span class="info-value flex items-center gap-2">
{#if dataSizeBytes}
<a
href="/{organization}/{project}/-/status/tables"
class="usage-pill-link"
>
<span class="usage-pill">
<span
class="usage-pill-fill"
class:over-cap={isOverCap}
style:width="{usagePercent}%"
></span>
</span>
</a>
<span class="text-xs text-fg-secondary whitespace-nowrap">
{formatMemorySize(Number(dataSizeBytes))}{#if storageCap}
/ {formatMemorySize(storageCap)}{/if}
</span>
{:else}
{/if}
</span>
</div>
{/if}
</div>
</OverviewCard>

Expand All @@ -177,6 +223,15 @@
.status-dot {
@apply w-2 h-2 rounded-full inline-block;
}
.usage-pill-link {
@apply no-underline;
}
.usage-pill {
@apply w-24 h-2.5 rounded-full bg-surface-subtle overflow-hidden inline-block;
}
.usage-pill-fill {
@apply h-full rounded-full bg-primary-500 block transition-all;
}
.repo-link {
@apply text-primary-500 text-sm;
}
Expand Down
11 changes: 10 additions & 1 deletion web-common/src/proto/gen/rill/runtime/v1/api_pb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// @ts-nocheck

import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
import { Message as Message$1, proto3, Struct, Timestamp } from "@bufbuild/protobuf";
import { Message as Message$1, proto3, protoInt64, Struct, Timestamp } from "@bufbuild/protobuf";
import { StructType } from "./schema_pb.js";
import { RefreshModelTrigger, Resource, ResourceName } from "./resources_pb.js";
import { ContentBlock, Tool } from "../../ai/v1/ai_pb.js";
Expand Down Expand Up @@ -792,6 +792,14 @@ export class GetInstanceResponse extends Message$1<GetInstanceResponse> {
*/
instance?: Instance;

/**
* data_size_bytes is the total size of the instance's data directory in bytes.
* This is the same value reported to billing/Orb as "data_dir_size_bytes".
*
* @generated from field: int64 data_size_bytes = 2;
*/
dataSizeBytes = protoInt64.zero;

constructor(data?: PartialMessage<GetInstanceResponse>) {
super();
proto3.util.initPartial(data, this);
Expand All @@ -801,6 +809,7 @@ export class GetInstanceResponse extends Message$1<GetInstanceResponse> {
static readonly typeName = "rill.runtime.v1.GetInstanceResponse";
static readonly fields: FieldList = proto3.util.newFieldList(() => [
{ no: 1, name: "instance", kind: "message", T: Instance },
{ no: 2, name: "data_size_bytes", kind: "scalar", T: 3 /* ScalarType.INT64 */ },
]);

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetInstanceResponse {
Expand Down
1 change: 1 addition & 0 deletions web-common/src/runtime-client/gen/index.schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ export interface V1GetFileResponse {

export interface V1GetInstanceResponse {
instance?: V1Instance;
dataSizeBytes?: string;
}

export interface V1GetLogsResponse {
Expand Down
Loading