Browse Source
ec is mostly working now
ec is mostly working now
* distribution of ec shards needs improvement * need configuration to enable ecworker-execute-ec-tasks
17 changed files with 3056 additions and 688 deletions
-
339weed/admin/dash/ec_shard_management.go
-
45weed/admin/dash/types.go
-
50weed/admin/handlers/cluster_handlers.go
-
10weed/admin/view/app/cluster_ec_shards.templ
-
165weed/admin/view/app/cluster_ec_shards_templ.go
-
490weed/admin/view/app/cluster_ec_volumes.templ
-
845weed/admin/view/app/cluster_ec_volumes_templ.go
-
2weed/admin/view/app/ec_volume_details.templ
-
2weed/admin/view/app/ec_volume_details_templ.go
-
2weed/admin/view/layout/layout.templ
-
2weed/admin/view/layout/layout_templ.go
-
23weed/pb/volume_server.proto
-
966weed/pb/volume_server_pb/volume_server.pb.go
-
43weed/pb/volume_server_pb/volume_server_grpc.pb.go
-
117weed/server/volume_grpc_copy.go
-
5weed/server/volume_server_handlers_admin.go
-
638weed/worker/tasks/erasure_coding/ec.go
@ -0,0 +1,490 @@ |
|||
package app |
|||
|
|||
import ( |
|||
"fmt" |
|||
"strings" |
|||
"github.com/seaweedfs/seaweedfs/weed/admin/dash" |
|||
) |
|||
|
|||
templ ClusterEcVolumes(data dash.ClusterEcVolumesData) { |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<title>EC Volumes - SeaweedFS</title> |
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> |
|||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"> |
|||
</head> |
|||
<body> |
|||
<div class="container-fluid"> |
|||
<div class="row"> |
|||
<div class="col-12"> |
|||
<h2 class="mb-4"> |
|||
<i class="fas fa-database me-2"></i>EC Volumes |
|||
<small class="text-muted">({fmt.Sprintf("%d", data.TotalVolumes)} volumes)</small> |
|||
</h2> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Statistics Cards --> |
|||
<div class="row mb-4"> |
|||
<div class="col-md-3"> |
|||
<div class="card text-bg-primary"> |
|||
<div class="card-body"> |
|||
<div class="d-flex justify-content-between"> |
|||
<div> |
|||
<h6 class="card-title">Total Volumes</h6> |
|||
<h4 class="mb-0">{fmt.Sprintf("%d", data.TotalVolumes)}</h4> |
|||
<small>EC encoded volumes</small> |
|||
</div> |
|||
<div class="align-self-center"> |
|||
<i class="fas fa-cubes fa-2x"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<div class="card text-bg-info"> |
|||
<div class="card-body"> |
|||
<div class="d-flex justify-content-between"> |
|||
<div> |
|||
<h6 class="card-title">Total Shards</h6> |
|||
<h4 class="mb-0">{fmt.Sprintf("%d", data.TotalShards)}</h4> |
|||
<small>Distributed shards</small> |
|||
</div> |
|||
<div class="align-self-center"> |
|||
<i class="fas fa-puzzle-piece fa-2x"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<div class="card text-bg-success"> |
|||
<div class="card-body"> |
|||
<div class="d-flex justify-content-between"> |
|||
<div> |
|||
<h6 class="card-title">Complete Volumes</h6> |
|||
<h4 class="mb-0">{fmt.Sprintf("%d", data.CompleteVolumes)}</h4> |
|||
<small>All shards present</small> |
|||
</div> |
|||
<div class="align-self-center"> |
|||
<i class="fas fa-check-circle fa-2x"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<div class="card text-bg-warning"> |
|||
<div class="card-body"> |
|||
<div class="d-flex justify-content-between"> |
|||
<div> |
|||
<h6 class="card-title">Incomplete Volumes</h6> |
|||
<h4 class="mb-0">{fmt.Sprintf("%d", data.IncompleteVolumes)}</h4> |
|||
<small>Missing shards</small> |
|||
</div> |
|||
<div class="align-self-center"> |
|||
<i class="fas fa-exclamation-triangle fa-2x"></i> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Volumes Table --> |
|||
<div class="d-flex justify-content-between align-items-center mb-3"> |
|||
<div class="d-flex align-items-center"> |
|||
<span class="me-3"> |
|||
Showing {fmt.Sprintf("%d", (data.Page-1)*data.PageSize + 1)} to {fmt.Sprintf("%d", func() int { |
|||
end := data.Page * data.PageSize |
|||
if end > data.TotalVolumes { |
|||
return data.TotalVolumes |
|||
} |
|||
return end |
|||
}())} of {fmt.Sprintf("%d", data.TotalVolumes)} volumes |
|||
</span> |
|||
|
|||
<div class="d-flex align-items-center"> |
|||
<label for="pageSize" class="form-label me-2 mb-0">Show:</label> |
|||
<select id="pageSize" class="form-select form-select-sm" style="width: auto;" onchange="changePageSize(this.value)"> |
|||
<option value="5" if data.PageSize == 5 { selected }>5</option> |
|||
<option value="10" if data.PageSize == 10 { selected }>10</option> |
|||
<option value="25" if data.PageSize == 25 { selected }>25</option> |
|||
<option value="50" if data.PageSize == 50 { selected }>50</option> |
|||
<option value="100" if data.PageSize == 100 { selected }>100</option> |
|||
</select> |
|||
<span class="ms-2">per page</span> |
|||
</div> |
|||
</div> |
|||
|
|||
if data.Collection != "" { |
|||
<div> |
|||
<span class="badge bg-info">Collection: {data.Collection}</span> |
|||
<a href="/cluster/ec-shards" class="btn btn-sm btn-outline-secondary ms-2">Clear Filter</a> |
|||
</div> |
|||
} |
|||
</div> |
|||
|
|||
<div class="table-responsive"> |
|||
<table class="table table-striped table-hover" id="ecVolumesTable"> |
|||
<thead> |
|||
<tr> |
|||
<th> |
|||
<a href="#" onclick="sortBy('volume_id')" class="text-dark text-decoration-none"> |
|||
Volume ID |
|||
if data.SortBy == "volume_id" { |
|||
if data.SortOrder == "asc" { |
|||
<i class="fas fa-sort-up ms-1"></i> |
|||
} else { |
|||
<i class="fas fa-sort-down ms-1"></i> |
|||
} |
|||
} else { |
|||
<i class="fas fa-sort ms-1 text-muted"></i> |
|||
} |
|||
</a> |
|||
</th> |
|||
if data.ShowCollectionColumn { |
|||
<th> |
|||
<a href="#" onclick="sortBy('collection')" class="text-dark text-decoration-none"> |
|||
Collection |
|||
if data.SortBy == "collection" { |
|||
if data.SortOrder == "asc" { |
|||
<i class="fas fa-sort-up ms-1"></i> |
|||
} else { |
|||
<i class="fas fa-sort-down ms-1"></i> |
|||
} |
|||
} else { |
|||
<i class="fas fa-sort ms-1 text-muted"></i> |
|||
} |
|||
</a> |
|||
</th> |
|||
} |
|||
<th> |
|||
<a href="#" onclick="sortBy('total_shards')" class="text-dark text-decoration-none"> |
|||
Shard Count |
|||
if data.SortBy == "total_shards" { |
|||
if data.SortOrder == "asc" { |
|||
<i class="fas fa-sort-up ms-1"></i> |
|||
} else { |
|||
<i class="fas fa-sort-down ms-1"></i> |
|||
} |
|||
} else { |
|||
<i class="fas fa-sort ms-1 text-muted"></i> |
|||
} |
|||
</a> |
|||
</th> |
|||
<th class="text-dark">Shard Locations</th> |
|||
<th> |
|||
<a href="#" onclick="sortBy('completeness')" class="text-dark text-decoration-none"> |
|||
Status |
|||
if data.SortBy == "completeness" { |
|||
if data.SortOrder == "asc" { |
|||
<i class="fas fa-sort-up ms-1"></i> |
|||
} else { |
|||
<i class="fas fa-sort-down ms-1"></i> |
|||
} |
|||
} else { |
|||
<i class="fas fa-sort ms-1 text-muted"></i> |
|||
} |
|||
</a> |
|||
</th> |
|||
if data.ShowDataCenterColumn { |
|||
<th class="text-dark">Data Centers</th> |
|||
} |
|||
<th class="text-dark">Actions</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
for _, volume := range data.EcVolumes { |
|||
<tr> |
|||
<td> |
|||
<strong>{fmt.Sprintf("%d", volume.VolumeID)}</strong> |
|||
</td> |
|||
if data.ShowCollectionColumn { |
|||
<td> |
|||
if volume.Collection != "" { |
|||
<span class="badge bg-outline-info">{volume.Collection}</span> |
|||
} else { |
|||
<span class="text-muted">default</span> |
|||
} |
|||
</td> |
|||
} |
|||
<td> |
|||
<span class="badge bg-primary">{fmt.Sprintf("%d/14", volume.TotalShards)}</span> |
|||
</td> |
|||
<td> |
|||
<div class="shard-locations" style="max-width: 400px;"> |
|||
@displayShardLocationsHTML(volume.ShardLocations) |
|||
</div> |
|||
</td> |
|||
<td> |
|||
if volume.IsComplete { |
|||
<span class="badge bg-success"> |
|||
<i class="fas fa-check me-1"></i>Complete |
|||
</span> |
|||
} else { |
|||
<span class="badge bg-warning"> |
|||
<i class="fas fa-exclamation-triangle me-1"></i> |
|||
Missing {fmt.Sprintf("%d", len(volume.MissingShards))} shards |
|||
</span> |
|||
if len(volume.MissingShards) > 0 { |
|||
<br/> |
|||
<small class="text-muted"> |
|||
Missing: {formatMissingShards(volume.MissingShards)} |
|||
</small> |
|||
} |
|||
} |
|||
</td> |
|||
if data.ShowDataCenterColumn { |
|||
<td> |
|||
for i, dc := range volume.DataCenters { |
|||
if i > 0 { |
|||
<span>, </span> |
|||
} |
|||
<span class="badge bg-primary text-white">{dc}</span> |
|||
} |
|||
</td> |
|||
} |
|||
<td> |
|||
<div class="btn-group" role="group"> |
|||
<button type="button" class="btn btn-sm btn-outline-primary" |
|||
onclick="showVolumeDetails(event)" |
|||
data-volume-id={ fmt.Sprintf("%d", volume.VolumeID) } |
|||
title="View EC volume details"> |
|||
<i class="fas fa-info-circle"></i> |
|||
</button> |
|||
if !volume.IsComplete { |
|||
<button type="button" class="btn btn-sm btn-outline-warning" |
|||
onclick="repairVolume(event)" |
|||
data-volume-id={ fmt.Sprintf("%d", volume.VolumeID) } |
|||
title="Repair missing shards"> |
|||
<i class="fas fa-wrench"></i> |
|||
</button> |
|||
} |
|||
</div> |
|||
</td> |
|||
</tr> |
|||
} |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
|
|||
<!-- Pagination --> |
|||
if data.TotalPages > 1 { |
|||
<nav aria-label="EC Volumes pagination"> |
|||
<ul class="pagination justify-content-center"> |
|||
if data.Page > 1 { |
|||
<li class="page-item"> |
|||
<a class="page-link" href="#" onclick="goToPage(event)" data-page="1">First</a> |
|||
</li> |
|||
<li class="page-item"> |
|||
<a class="page-link" href="#" onclick="goToPage(event)" data-page={ fmt.Sprintf("%d", data.Page-1) }>Previous</a> |
|||
</li> |
|||
} |
|||
|
|||
for i := 1; i <= data.TotalPages; i++ { |
|||
if i == data.Page { |
|||
<li class="page-item active"> |
|||
<span class="page-link">{fmt.Sprintf("%d", i)}</span> |
|||
</li> |
|||
} else if i <= 3 || i > data.TotalPages-3 || (i >= data.Page-2 && i <= data.Page+2) { |
|||
<li class="page-item"> |
|||
<a class="page-link" href="#" onclick="goToPage(event)" data-page={ fmt.Sprintf("%d", i) }>{fmt.Sprintf("%d", i)}</a> |
|||
</li> |
|||
} else if i == 4 && data.Page > 6 { |
|||
<li class="page-item disabled"> |
|||
<span class="page-link">...</span> |
|||
</li> |
|||
} else if i == data.TotalPages-3 && data.Page < data.TotalPages-5 { |
|||
<li class="page-item disabled"> |
|||
<span class="page-link">...</span> |
|||
</li> |
|||
} |
|||
} |
|||
|
|||
if data.Page < data.TotalPages { |
|||
<li class="page-item"> |
|||
<a class="page-link" href="#" onclick="goToPage(event)" data-page={ fmt.Sprintf("%d", data.Page+1) }>Next</a> |
|||
</li> |
|||
<li class="page-item"> |
|||
<a class="page-link" href="#" onclick="goToPage(event)" data-page={ fmt.Sprintf("%d", data.TotalPages) }>Last</a> |
|||
</li> |
|||
} |
|||
</ul> |
|||
</nav> |
|||
} |
|||
</div> |
|||
|
|||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> |
|||
<script> |
|||
// Sorting functionality |
|||
function sortBy(field) { |
|||
const currentSort = new URLSearchParams(window.location.search).get('sort_by'); |
|||
const currentOrder = new URLSearchParams(window.location.search).get('sort_order') || 'asc'; |
|||
|
|||
let newOrder = 'asc'; |
|||
if (currentSort === field && currentOrder === 'asc') { |
|||
newOrder = 'desc'; |
|||
} |
|||
|
|||
const url = new URL(window.location); |
|||
url.searchParams.set('sort_by', field); |
|||
url.searchParams.set('sort_order', newOrder); |
|||
url.searchParams.set('page', '1'); // Reset to first page |
|||
window.location.href = url.toString(); |
|||
} |
|||
|
|||
// Pagination functionality |
|||
function goToPage(event) { |
|||
event.preventDefault(); |
|||
const page = event.target.closest('a').getAttribute('data-page'); |
|||
const url = new URL(window.location); |
|||
url.searchParams.set('page', page); |
|||
window.location.href = url.toString(); |
|||
} |
|||
|
|||
// Page size functionality |
|||
function changePageSize(newPageSize) { |
|||
const url = new URL(window.location); |
|||
url.searchParams.set('page_size', newPageSize); |
|||
url.searchParams.set('page', '1'); // Reset to first page when changing page size |
|||
window.location.href = url.toString(); |
|||
} |
|||
|
|||
// Volume details |
|||
function showVolumeDetails(event) { |
|||
const volumeId = event.target.closest('button').getAttribute('data-volume-id'); |
|||
window.location.href = `/cluster/ec-volumes/${volumeId}`; |
|||
} |
|||
|
|||
// Repair volume |
|||
function repairVolume(event) { |
|||
const volumeId = event.target.closest('button').getAttribute('data-volume-id'); |
|||
if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) { |
|||
// TODO: Implement repair functionality |
|||
alert('Repair functionality will be implemented soon.'); |
|||
} |
|||
} |
|||
</script> |
|||
</body> |
|||
</html> |
|||
} |
|||
|
|||
// displayShardLocationsHTML renders shard locations as proper HTML |
|||
templ displayShardLocationsHTML(shardLocations map[int]string) { |
|||
if len(shardLocations) == 0 { |
|||
<span class="text-muted">No shards</span> |
|||
} else { |
|||
for i, serverInfo := range groupShardsByServer(shardLocations) { |
|||
if i > 0 { |
|||
<br/> |
|||
} |
|||
<strong> |
|||
<a href={ templ.URL("/cluster/volume-servers/" + serverInfo.Server) } class="text-primary text-decoration-none"> |
|||
{ serverInfo.Server } |
|||
</a>: |
|||
</strong> { serverInfo.ShardRanges } |
|||
} |
|||
} |
|||
} |
|||
|
|||
// ServerShardInfo represents server and its shard ranges |
|||
type ServerShardInfo struct { |
|||
Server string |
|||
ShardRanges string |
|||
} |
|||
|
|||
// groupShardsByServer groups shards by server and formats ranges |
|||
func groupShardsByServer(shardLocations map[int]string) []ServerShardInfo { |
|||
if len(shardLocations) == 0 { |
|||
return []ServerShardInfo{} |
|||
} |
|||
|
|||
// Group shards by server |
|||
serverShards := make(map[string][]int) |
|||
for shardId, server := range shardLocations { |
|||
serverShards[server] = append(serverShards[server], shardId) |
|||
} |
|||
|
|||
var serverInfos []ServerShardInfo |
|||
for server, shards := range serverShards { |
|||
// Sort shards for each server |
|||
for i := 0; i < len(shards); i++ { |
|||
for j := i + 1; j < len(shards); j++ { |
|||
if shards[i] > shards[j] { |
|||
shards[i], shards[j] = shards[j], shards[i] |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Format shard ranges compactly |
|||
shardRanges := formatShardRanges(shards) |
|||
serverInfos = append(serverInfos, ServerShardInfo{ |
|||
Server: server, |
|||
ShardRanges: shardRanges, |
|||
}) |
|||
} |
|||
|
|||
// Sort by server name |
|||
for i := 0; i < len(serverInfos); i++ { |
|||
for j := i + 1; j < len(serverInfos); j++ { |
|||
if serverInfos[i].Server > serverInfos[j].Server { |
|||
serverInfos[i], serverInfos[j] = serverInfos[j], serverInfos[i] |
|||
} |
|||
} |
|||
} |
|||
|
|||
return serverInfos |
|||
} |
|||
|
|||
// Helper function to format shard ranges compactly (e.g., "0-3,7,9-11") |
|||
func formatShardRanges(shards []int) string { |
|||
if len(shards) == 0 { |
|||
return "" |
|||
} |
|||
|
|||
var ranges []string |
|||
start := shards[0] |
|||
end := shards[0] |
|||
|
|||
for i := 1; i < len(shards); i++ { |
|||
if shards[i] == end+1 { |
|||
end = shards[i] |
|||
} else { |
|||
if start == end { |
|||
ranges = append(ranges, fmt.Sprintf("%d", start)) |
|||
} else { |
|||
ranges = append(ranges, fmt.Sprintf("%d-%d", start, end)) |
|||
} |
|||
start = shards[i] |
|||
end = shards[i] |
|||
} |
|||
} |
|||
|
|||
// Add the last range |
|||
if start == end { |
|||
ranges = append(ranges, fmt.Sprintf("%d", start)) |
|||
} else { |
|||
ranges = append(ranges, fmt.Sprintf("%d-%d", start, end)) |
|||
} |
|||
|
|||
return strings.Join(ranges, ",") |
|||
} |
|||
|
|||
// Helper function to format missing shards |
|||
func formatMissingShards(missingShards []int) string { |
|||
if len(missingShards) == 0 { |
|||
return "" |
|||
} |
|||
|
|||
var shardStrs []string |
|||
for _, shard := range missingShards { |
|||
shardStrs = append(shardStrs, fmt.Sprintf("%d", shard)) |
|||
} |
|||
|
|||
return strings.Join(shardStrs, ", ") |
|||
} |
|||
@ -0,0 +1,845 @@ |
|||
// Code generated by templ - DO NOT EDIT.
|
|||
|
|||
// templ: version: v0.3.906
|
|||
package app |
|||
|
|||
//lint:file-ignore SA4006 This context is only used if a nested component is present.
|
|||
|
|||
import "github.com/a-h/templ" |
|||
import templruntime "github.com/a-h/templ/runtime" |
|||
|
|||
import ( |
|||
"fmt" |
|||
"github.com/seaweedfs/seaweedfs/weed/admin/dash" |
|||
"strings" |
|||
) |
|||
|
|||
func ClusterEcVolumes(data dash.ClusterEcVolumesData) templ.Component { |
|||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
|||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context |
|||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { |
|||
return templ_7745c5c3_CtxErr |
|||
} |
|||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) |
|||
if !templ_7745c5c3_IsBuffer { |
|||
defer func() { |
|||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) |
|||
if templ_7745c5c3_Err == nil { |
|||
templ_7745c5c3_Err = templ_7745c5c3_BufErr |
|||
} |
|||
}() |
|||
} |
|||
ctx = templ.InitializeContext(ctx) |
|||
templ_7745c5c3_Var1 := templ.GetChildren(ctx) |
|||
if templ_7745c5c3_Var1 == nil { |
|||
templ_7745c5c3_Var1 = templ.NopComponent |
|||
} |
|||
ctx = templ.ClearChildren(ctx) |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><title>EC Volumes - SeaweedFS</title><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css\" rel=\"stylesheet\"><link href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css\" rel=\"stylesheet\"></head><body><div class=\"container-fluid\"><div class=\"row\"><div class=\"col-12\"><h2 class=\"mb-4\"><i class=\"fas fa-database me-2\"></i>EC Volumes <small class=\"text-muted\">(") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var2 string |
|||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalVolumes)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 25, Col: 84} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " volumes)</small></h2></div></div><!-- Statistics Cards --><div class=\"row mb-4\"><div class=\"col-md-3\"><div class=\"card text-bg-primary\"><div class=\"card-body\"><div class=\"d-flex justify-content-between\"><div><h6 class=\"card-title\">Total Volumes</h6><h4 class=\"mb-0\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var3 string |
|||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalVolumes)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 38, Col: 86} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h4><small>EC encoded volumes</small></div><div class=\"align-self-center\"><i class=\"fas fa-cubes fa-2x\"></i></div></div></div></div></div><div class=\"col-md-3\"><div class=\"card text-bg-info\"><div class=\"card-body\"><div class=\"d-flex justify-content-between\"><div><h6 class=\"card-title\">Total Shards</h6><h4 class=\"mb-0\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var4 string |
|||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalShards)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 54, Col: 85} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</h4><small>Distributed shards</small></div><div class=\"align-self-center\"><i class=\"fas fa-puzzle-piece fa-2x\"></i></div></div></div></div></div><div class=\"col-md-3\"><div class=\"card text-bg-success\"><div class=\"card-body\"><div class=\"d-flex justify-content-between\"><div><h6 class=\"card-title\">Complete Volumes</h6><h4 class=\"mb-0\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var5 string |
|||
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.CompleteVolumes)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 70, Col: 89} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</h4><small>All shards present</small></div><div class=\"align-self-center\"><i class=\"fas fa-check-circle fa-2x\"></i></div></div></div></div></div><div class=\"col-md-3\"><div class=\"card text-bg-warning\"><div class=\"card-body\"><div class=\"d-flex justify-content-between\"><div><h6 class=\"card-title\">Incomplete Volumes</h6><h4 class=\"mb-0\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var6 string |
|||
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.IncompleteVolumes)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 86, Col: 91} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</h4><small>Missing shards</small></div><div class=\"align-self-center\"><i class=\"fas fa-exclamation-triangle fa-2x\"></i></div></div></div></div></div></div><!-- Volumes Table --><div class=\"d-flex justify-content-between align-items-center mb-3\"><div class=\"d-flex align-items-center\"><span class=\"me-3\">Showing ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var7 string |
|||
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", (data.Page-1)*data.PageSize+1)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 102, Col: 79} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " to ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var8 string |
|||
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", func() int { |
|||
end := data.Page * data.PageSize |
|||
if end > data.TotalVolumes { |
|||
return data.TotalVolumes |
|||
} |
|||
return end |
|||
}())) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 108, Col: 24} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, " of ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var9 string |
|||
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalVolumes)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 108, Col: 66} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " volumes</span><div class=\"d-flex align-items-center\"><label for=\"pageSize\" class=\"form-label me-2 mb-0\">Show:</label> <select id=\"pageSize\" class=\"form-select form-select-sm\" style=\"width: auto;\" onchange=\"changePageSize(this.value)\"><option value=\"5\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.PageSize == 5 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " selected") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, ">5</option> <option value=\"10\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.PageSize == 10 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " selected") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, ">10</option> <option value=\"25\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.PageSize == 25 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, " selected") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, ">25</option> <option value=\"50\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.PageSize == 50 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " selected") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, ">50</option> <option value=\"100\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.PageSize == 100 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " selected") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, ">100</option></select> <span class=\"ms-2\">per page</span></div></div>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.Collection != "" { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div><span class=\"badge bg-info\">Collection: ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var10 string |
|||
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(data.Collection) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 126, Col: 76} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</span> <a href=\"/cluster/ec-shards\" class=\"btn btn-sm btn-outline-secondary ms-2\">Clear Filter</a></div>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</div><div class=\"table-responsive\"><table class=\"table table-striped table-hover\" id=\"ecVolumesTable\"><thead><tr><th><a href=\"#\" onclick=\"sortBy('volume_id')\" class=\"text-dark text-decoration-none\">Volume ID ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.SortBy == "volume_id" { |
|||
if data.SortOrder == "asc" { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "<i class=\"fas fa-sort-up ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<i class=\"fas fa-sort-down ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<i class=\"fas fa-sort ms-1 text-muted\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</a></th>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.ShowCollectionColumn { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<th><a href=\"#\" onclick=\"sortBy('collection')\" class=\"text-dark text-decoration-none\">Collection ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.SortBy == "collection" { |
|||
if data.SortOrder == "asc" { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<i class=\"fas fa-sort-up ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "<i class=\"fas fa-sort-down ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<i class=\"fas fa-sort ms-1 text-muted\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</a></th>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<th><a href=\"#\" onclick=\"sortBy('total_shards')\" class=\"text-dark text-decoration-none\">Shard Count ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.SortBy == "total_shards" { |
|||
if data.SortOrder == "asc" { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "<i class=\"fas fa-sort-up ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<i class=\"fas fa-sort-down ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "<i class=\"fas fa-sort ms-1 text-muted\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</a></th><th class=\"text-dark\">Shard Locations</th><th><a href=\"#\" onclick=\"sortBy('completeness')\" class=\"text-dark text-decoration-none\">Status ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.SortBy == "completeness" { |
|||
if data.SortOrder == "asc" { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "<i class=\"fas fa-sort-up ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "<i class=\"fas fa-sort-down ms-1\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "<i class=\"fas fa-sort ms-1 text-muted\"></i>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "</a></th>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.ShowDataCenterColumn { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "<th class=\"text-dark\">Data Centers</th>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<th class=\"text-dark\">Actions</th></tr></thead> <tbody>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
for _, volume := range data.EcVolumes { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "<tr><td><strong>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var11 string |
|||
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", volume.VolumeID)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 205, Col: 75} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "</strong></td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.ShowCollectionColumn { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "<td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if volume.Collection != "" { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "<span class=\"badge bg-outline-info\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var12 string |
|||
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(volume.Collection) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 210, Col: 94} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, "</span>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<span class=\"text-muted\">default</span>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "<td><span class=\"badge bg-primary\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var13 string |
|||
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d/14", volume.TotalShards)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 217, Col: 104} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</span></td><td><div class=\"shard-locations\" style=\"max-width: 400px;\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = displayShardLocationsHTML(volume.ShardLocations).Render(ctx, templ_7745c5c3_Buffer) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "</div></td><td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if volume.IsComplete { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "<span class=\"badge bg-success\"><i class=\"fas fa-check me-1\"></i>Complete</span>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "<span class=\"badge bg-warning\"><i class=\"fas fa-exclamation-triangle me-1\"></i> Missing ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var14 string |
|||
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", len(volume.MissingShards))) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 232, Col: 93} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, " shards</span> ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if len(volume.MissingShards) > 0 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<br><small class=\"text-muted\">Missing: ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var15 string |
|||
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(formatMissingShards(volume.MissingShards)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 237, Col: 95} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "</small>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "</td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.ShowDataCenterColumn { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "<td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
for i, dc := range volume.DataCenters { |
|||
if i > 0 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "<span>, </span>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, " <span class=\"badge bg-primary text-white\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var16 string |
|||
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(dc) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 248, Col: 85} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "</span>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "</td>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "<td><div class=\"btn-group\" role=\"group\"><button type=\"button\" class=\"btn btn-sm btn-outline-primary\" onclick=\"showVolumeDetails(event)\" data-volume-id=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var17 string |
|||
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", volume.VolumeID)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 256, Col: 95} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "\" title=\"View EC volume details\"><i class=\"fas fa-info-circle\"></i></button> ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if !volume.IsComplete { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "<button type=\"button\" class=\"btn btn-sm btn-outline-warning\" onclick=\"repairVolume(event)\" data-volume-id=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var18 string |
|||
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", volume.VolumeID)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 263, Col: 99} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "\" title=\"Repair missing shards\"><i class=\"fas fa-wrench\"></i></button>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "</div></td></tr>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "</tbody></table></div><!-- Pagination -->") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.TotalPages > 1 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "<nav aria-label=\"EC Volumes pagination\"><ul class=\"pagination justify-content-center\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
if data.Page > 1 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "<li class=\"page-item\"><a class=\"page-link\" href=\"#\" onclick=\"goToPage(event)\" data-page=\"1\">First</a></li><li class=\"page-item\"><a class=\"page-link\" href=\"#\" onclick=\"goToPage(event)\" data-page=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var19 string |
|||
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.Page-1)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 285, Col: 126} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "\">Previous</a></li>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
for i := 1; i <= data.TotalPages; i++ { |
|||
if i == data.Page { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "<li class=\"page-item active\"><span class=\"page-link\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var20 string |
|||
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", i)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 292, Col: 77} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "</span></li>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else if i <= 3 || i > data.TotalPages-3 || (i >= data.Page-2 && i <= data.Page+2) { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "<li class=\"page-item\"><a class=\"page-link\" href=\"#\" onclick=\"goToPage(event)\" data-page=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var21 string |
|||
templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", i)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 296, Col: 120} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var22 string |
|||
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", i)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 296, Col: 144} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "</a></li>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else if i == 4 && data.Page > 6 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "<li class=\"page-item disabled\"><span class=\"page-link\">...</span></li>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else if i == data.TotalPages-3 && data.Page < data.TotalPages-5 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "<li class=\"page-item disabled\"><span class=\"page-link\">...</span></li>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} |
|||
if data.Page < data.TotalPages { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "<li class=\"page-item\"><a class=\"page-link\" href=\"#\" onclick=\"goToPage(event)\" data-page=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var23 string |
|||
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.Page+1)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 311, Col: 126} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "\">Next</a></li><li class=\"page-item\"><a class=\"page-link\" href=\"#\" onclick=\"goToPage(event)\" data-page=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var24 string |
|||
templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", data.TotalPages)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 314, Col: 130} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "\">Last</a></li>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "</ul></nav>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "</div><script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js\"></script><script>\n // Sorting functionality\n function sortBy(field) {\n const currentSort = new URLSearchParams(window.location.search).get('sort_by');\n const currentOrder = new URLSearchParams(window.location.search).get('sort_order') || 'asc';\n \n let newOrder = 'asc';\n if (currentSort === field && currentOrder === 'asc') {\n newOrder = 'desc';\n }\n \n const url = new URL(window.location);\n url.searchParams.set('sort_by', field);\n url.searchParams.set('sort_order', newOrder);\n url.searchParams.set('page', '1'); // Reset to first page\n window.location.href = url.toString();\n }\n\n // Pagination functionality\n function goToPage(event) {\n event.preventDefault();\n const page = event.target.closest('a').getAttribute('data-page');\n const url = new URL(window.location);\n url.searchParams.set('page', page);\n window.location.href = url.toString();\n }\n\n // Page size functionality\n function changePageSize(newPageSize) {\n const url = new URL(window.location);\n url.searchParams.set('page_size', newPageSize);\n url.searchParams.set('page', '1'); // Reset to first page when changing page size\n window.location.href = url.toString();\n }\n\n // Volume details\n function showVolumeDetails(event) {\n const volumeId = event.target.closest('button').getAttribute('data-volume-id');\n window.location.href = `/cluster/ec-volumes/${volumeId}`;\n }\n\n // Repair volume\n function repairVolume(event) {\n const volumeId = event.target.closest('button').getAttribute('data-volume-id');\n if (confirm(`Are you sure you want to repair missing shards for volume ${volumeId}?`)) {\n // TODO: Implement repair functionality\n alert('Repair functionality will be implemented soon.');\n }\n }\n </script></body></html>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
return nil |
|||
}) |
|||
} |
|||
|
|||
// displayShardLocationsHTML renders shard locations as proper HTML
|
|||
func displayShardLocationsHTML(shardLocations map[int]string) templ.Component { |
|||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { |
|||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context |
|||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { |
|||
return templ_7745c5c3_CtxErr |
|||
} |
|||
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) |
|||
if !templ_7745c5c3_IsBuffer { |
|||
defer func() { |
|||
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) |
|||
if templ_7745c5c3_Err == nil { |
|||
templ_7745c5c3_Err = templ_7745c5c3_BufErr |
|||
} |
|||
}() |
|||
} |
|||
ctx = templ.InitializeContext(ctx) |
|||
templ_7745c5c3_Var25 := templ.GetChildren(ctx) |
|||
if templ_7745c5c3_Var25 == nil { |
|||
templ_7745c5c3_Var25 = templ.NopComponent |
|||
} |
|||
ctx = templ.ClearChildren(ctx) |
|||
if len(shardLocations) == 0 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<span class=\"text-muted\">No shards</span>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} else { |
|||
for i, serverInfo := range groupShardsByServer(shardLocations) { |
|||
if i > 0 { |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "<br>") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, " <strong><a href=\"") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var26 templ.SafeURL |
|||
templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/cluster/volume-servers/" + serverInfo.Server)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 387, Col: 71} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 88, "\" class=\"text-primary text-decoration-none\">") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var27 string |
|||
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(serverInfo.Server) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 388, Col: 24} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 89, "</a>:</strong> ") |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
var templ_7745c5c3_Var28 string |
|||
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinStringErrs(serverInfo.ShardRanges) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `view/app/cluster_ec_volumes.templ`, Line: 390, Col: 37} |
|||
} |
|||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28)) |
|||
if templ_7745c5c3_Err != nil { |
|||
return templ_7745c5c3_Err |
|||
} |
|||
} |
|||
} |
|||
return nil |
|||
}) |
|||
} |
|||
|
|||
// ServerShardInfo represents server and its shard ranges
|
|||
type ServerShardInfo struct { |
|||
Server string |
|||
ShardRanges string |
|||
} |
|||
|
|||
// groupShardsByServer groups shards by server and formats ranges
|
|||
func groupShardsByServer(shardLocations map[int]string) []ServerShardInfo { |
|||
if len(shardLocations) == 0 { |
|||
return []ServerShardInfo{} |
|||
} |
|||
|
|||
// Group shards by server
|
|||
serverShards := make(map[string][]int) |
|||
for shardId, server := range shardLocations { |
|||
serverShards[server] = append(serverShards[server], shardId) |
|||
} |
|||
|
|||
var serverInfos []ServerShardInfo |
|||
for server, shards := range serverShards { |
|||
// Sort shards for each server
|
|||
for i := 0; i < len(shards); i++ { |
|||
for j := i + 1; j < len(shards); j++ { |
|||
if shards[i] > shards[j] { |
|||
shards[i], shards[j] = shards[j], shards[i] |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Format shard ranges compactly
|
|||
shardRanges := formatShardRanges(shards) |
|||
serverInfos = append(serverInfos, ServerShardInfo{ |
|||
Server: server, |
|||
ShardRanges: shardRanges, |
|||
}) |
|||
} |
|||
|
|||
// Sort by server name
|
|||
for i := 0; i < len(serverInfos); i++ { |
|||
for j := i + 1; j < len(serverInfos); j++ { |
|||
if serverInfos[i].Server > serverInfos[j].Server { |
|||
serverInfos[i], serverInfos[j] = serverInfos[j], serverInfos[i] |
|||
} |
|||
} |
|||
} |
|||
|
|||
return serverInfos |
|||
} |
|||
|
|||
// Helper function to format shard ranges compactly (e.g., "0-3,7,9-11")
|
|||
func formatShardRanges(shards []int) string { |
|||
if len(shards) == 0 { |
|||
return "" |
|||
} |
|||
|
|||
var ranges []string |
|||
start := shards[0] |
|||
end := shards[0] |
|||
|
|||
for i := 1; i < len(shards); i++ { |
|||
if shards[i] == end+1 { |
|||
end = shards[i] |
|||
} else { |
|||
if start == end { |
|||
ranges = append(ranges, fmt.Sprintf("%d", start)) |
|||
} else { |
|||
ranges = append(ranges, fmt.Sprintf("%d-%d", start, end)) |
|||
} |
|||
start = shards[i] |
|||
end = shards[i] |
|||
} |
|||
} |
|||
|
|||
// Add the last range
|
|||
if start == end { |
|||
ranges = append(ranges, fmt.Sprintf("%d", start)) |
|||
} else { |
|||
ranges = append(ranges, fmt.Sprintf("%d-%d", start, end)) |
|||
} |
|||
|
|||
return strings.Join(ranges, ",") |
|||
} |
|||
|
|||
// Helper function to format missing shards
|
|||
func formatMissingShards(missingShards []int) string { |
|||
if len(missingShards) == 0 { |
|||
return "" |
|||
} |
|||
|
|||
var shardStrs []string |
|||
for _, shard := range missingShards { |
|||
shardStrs = append(shardStrs, fmt.Sprintf("%d", shard)) |
|||
} |
|||
|
|||
return strings.Join(shardStrs, ", ") |
|||
} |
|||
|
|||
var _ = templruntime.GeneratedTemplate |
|||
966
weed/pb/volume_server_pb/volume_server.pb.go
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue