| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- package dash
- import (
- "context"
- "sort"
- "time"
- "github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
- )
- // GetClusterCollections retrieves cluster collections data
- func (s *AdminServer) GetClusterCollections() (*ClusterCollectionsData, error) {
- var collections []CollectionInfo
- var totalVolumes int
- var totalEcVolumes int
- var totalFiles int64
- var totalSize int64
- collectionMap := make(map[string]*CollectionInfo)
- // Get actual collection information from volume data
- err := s.WithMasterClient(func(client master_pb.SeaweedClient) error {
- resp, err := client.VolumeList(context.Background(), &master_pb.VolumeListRequest{})
- if err != nil {
- return err
- }
- if resp.TopologyInfo != nil {
- for _, dc := range resp.TopologyInfo.DataCenterInfos {
- for _, rack := range dc.RackInfos {
- for _, node := range rack.DataNodeInfos {
- for _, diskInfo := range node.DiskInfos {
- // Process regular volumes
- for _, volInfo := range diskInfo.VolumeInfos {
- // Extract collection name from volume info
- collectionName := volInfo.Collection
- if collectionName == "" {
- collectionName = "default" // Default collection for volumes without explicit collection
- }
- // Get disk type from volume info, default to hdd if empty
- diskType := volInfo.DiskType
- if diskType == "" {
- diskType = "hdd"
- }
- // Get or create collection info
- if collection, exists := collectionMap[collectionName]; exists {
- collection.VolumeCount++
- collection.FileCount += int64(volInfo.FileCount)
- collection.TotalSize += int64(volInfo.Size)
- // Update data center if this collection spans multiple DCs
- if collection.DataCenter != dc.Id && collection.DataCenter != "multi" {
- collection.DataCenter = "multi"
- }
- // Add disk type if not already present
- diskTypeExists := false
- for _, existingDiskType := range collection.DiskTypes {
- if existingDiskType == diskType {
- diskTypeExists = true
- break
- }
- }
- if !diskTypeExists {
- collection.DiskTypes = append(collection.DiskTypes, diskType)
- }
- totalVolumes++
- totalFiles += int64(volInfo.FileCount)
- totalSize += int64(volInfo.Size)
- } else {
- newCollection := CollectionInfo{
- Name: collectionName,
- DataCenter: dc.Id,
- VolumeCount: 1,
- EcVolumeCount: 0,
- FileCount: int64(volInfo.FileCount),
- TotalSize: int64(volInfo.Size),
- DiskTypes: []string{diskType},
- }
- collectionMap[collectionName] = &newCollection
- totalVolumes++
- totalFiles += int64(volInfo.FileCount)
- totalSize += int64(volInfo.Size)
- }
- }
- // Process EC volumes
- ecVolumeMap := make(map[uint32]bool) // Track unique EC volumes to avoid double counting
- for _, ecShardInfo := range diskInfo.EcShardInfos {
- // Extract collection name from EC shard info
- collectionName := ecShardInfo.Collection
- if collectionName == "" {
- collectionName = "default" // Default collection for EC volumes without explicit collection
- }
- // Only count each EC volume once (not per shard)
- if !ecVolumeMap[ecShardInfo.Id] {
- ecVolumeMap[ecShardInfo.Id] = true
- // Get disk type from disk info, default to hdd if empty
- diskType := diskInfo.Type
- if diskType == "" {
- diskType = "hdd"
- }
- // Get or create collection info
- if collection, exists := collectionMap[collectionName]; exists {
- collection.EcVolumeCount++
- // Update data center if this collection spans multiple DCs
- if collection.DataCenter != dc.Id && collection.DataCenter != "multi" {
- collection.DataCenter = "multi"
- }
- // Add disk type if not already present
- diskTypeExists := false
- for _, existingDiskType := range collection.DiskTypes {
- if existingDiskType == diskType {
- diskTypeExists = true
- break
- }
- }
- if !diskTypeExists {
- collection.DiskTypes = append(collection.DiskTypes, diskType)
- }
- totalEcVolumes++
- } else {
- newCollection := CollectionInfo{
- Name: collectionName,
- DataCenter: dc.Id,
- VolumeCount: 0,
- EcVolumeCount: 1,
- FileCount: 0,
- TotalSize: 0,
- DiskTypes: []string{diskType},
- }
- collectionMap[collectionName] = &newCollection
- totalEcVolumes++
- }
- }
- }
- }
- }
- }
- }
- }
- return nil
- })
- if err != nil {
- return nil, err
- }
- // Convert map to slice
- for _, collection := range collectionMap {
- collections = append(collections, *collection)
- }
- // Sort collections alphabetically by name
- sort.Slice(collections, func(i, j int) bool {
- return collections[i].Name < collections[j].Name
- })
- // If no collections found, show a message indicating no collections exist
- if len(collections) == 0 {
- // Return empty collections data instead of creating fake ones
- return &ClusterCollectionsData{
- Collections: []CollectionInfo{},
- TotalCollections: 0,
- TotalVolumes: 0,
- TotalEcVolumes: 0,
- TotalFiles: 0,
- TotalSize: 0,
- LastUpdated: time.Now(),
- }, nil
- }
- return &ClusterCollectionsData{
- Collections: collections,
- TotalCollections: len(collections),
- TotalVolumes: totalVolumes,
- TotalEcVolumes: totalEcVolumes,
- TotalFiles: totalFiles,
- TotalSize: totalSize,
- LastUpdated: time.Now(),
- }, nil
- }
- // GetCollectionDetails retrieves detailed information for a specific collection including volumes and EC volumes
- func (s *AdminServer) GetCollectionDetails(collectionName string, page int, pageSize int, sortBy string, sortOrder string) (*CollectionDetailsData, error) {
- // Set defaults
- if page < 1 {
- page = 1
- }
- if pageSize < 1 || pageSize > 1000 {
- pageSize = 25
- }
- if sortBy == "" {
- sortBy = "volume_id"
- }
- if sortOrder == "" {
- sortOrder = "asc"
- }
- var regularVolumes []VolumeWithTopology
- var ecVolumes []EcVolumeWithShards
- var totalFiles int64
- var totalSize int64
- dataCenters := make(map[string]bool)
- diskTypes := make(map[string]bool)
- // Get regular volumes for this collection
- regularVolumeData, err := s.GetClusterVolumes(1, 10000, "volume_id", "asc", collectionName) // Get all volumes
- if err != nil {
- return nil, err
- }
- regularVolumes = regularVolumeData.Volumes
- totalSize = regularVolumeData.TotalSize
- // Calculate total files from regular volumes
- for _, vol := range regularVolumes {
- totalFiles += int64(vol.FileCount)
- }
- // Collect data centers and disk types from regular volumes
- for _, vol := range regularVolumes {
- dataCenters[vol.DataCenter] = true
- diskTypes[vol.DiskType] = true
- }
- // Get EC volumes for this collection
- ecVolumeData, err := s.GetClusterEcVolumes(1, 10000, "volume_id", "asc", collectionName) // Get all EC volumes
- if err != nil {
- return nil, err
- }
- ecVolumes = ecVolumeData.EcVolumes
- // Collect data centers from EC volumes
- for _, ecVol := range ecVolumes {
- for _, dc := range ecVol.DataCenters {
- dataCenters[dc] = true
- }
- }
- // Combine all volumes for sorting and pagination
- type VolumeForSorting struct {
- Type string // "regular" or "ec"
- RegularVolume *VolumeWithTopology
- EcVolume *EcVolumeWithShards
- }
- var allVolumes []VolumeForSorting
- for i := range regularVolumes {
- allVolumes = append(allVolumes, VolumeForSorting{
- Type: "regular",
- RegularVolume: ®ularVolumes[i],
- })
- }
- for i := range ecVolumes {
- allVolumes = append(allVolumes, VolumeForSorting{
- Type: "ec",
- EcVolume: &ecVolumes[i],
- })
- }
- // Sort all volumes
- sort.Slice(allVolumes, func(i, j int) bool {
- var less bool
- switch sortBy {
- case "volume_id":
- var idI, idJ uint32
- if allVolumes[i].Type == "regular" {
- idI = allVolumes[i].RegularVolume.Id
- } else {
- idI = allVolumes[i].EcVolume.VolumeID
- }
- if allVolumes[j].Type == "regular" {
- idJ = allVolumes[j].RegularVolume.Id
- } else {
- idJ = allVolumes[j].EcVolume.VolumeID
- }
- less = idI < idJ
- case "type":
- // Sort by type first (regular before ec), then by volume ID
- if allVolumes[i].Type == allVolumes[j].Type {
- var idI, idJ uint32
- if allVolumes[i].Type == "regular" {
- idI = allVolumes[i].RegularVolume.Id
- } else {
- idI = allVolumes[i].EcVolume.VolumeID
- }
- if allVolumes[j].Type == "regular" {
- idJ = allVolumes[j].RegularVolume.Id
- } else {
- idJ = allVolumes[j].EcVolume.VolumeID
- }
- less = idI < idJ
- } else {
- less = allVolumes[i].Type < allVolumes[j].Type // "ec" < "regular"
- }
- default:
- // Default to volume ID sort
- var idI, idJ uint32
- if allVolumes[i].Type == "regular" {
- idI = allVolumes[i].RegularVolume.Id
- } else {
- idI = allVolumes[i].EcVolume.VolumeID
- }
- if allVolumes[j].Type == "regular" {
- idJ = allVolumes[j].RegularVolume.Id
- } else {
- idJ = allVolumes[j].EcVolume.VolumeID
- }
- less = idI < idJ
- }
- if sortOrder == "desc" {
- return !less
- }
- return less
- })
- // Apply pagination
- totalVolumesAndEc := len(allVolumes)
- totalPages := (totalVolumesAndEc + pageSize - 1) / pageSize
- startIndex := (page - 1) * pageSize
- endIndex := startIndex + pageSize
- if endIndex > totalVolumesAndEc {
- endIndex = totalVolumesAndEc
- }
- if startIndex >= totalVolumesAndEc {
- startIndex = 0
- endIndex = 0
- }
- // Extract paginated results
- var paginatedRegularVolumes []VolumeWithTopology
- var paginatedEcVolumes []EcVolumeWithShards
- for i := startIndex; i < endIndex; i++ {
- if allVolumes[i].Type == "regular" {
- paginatedRegularVolumes = append(paginatedRegularVolumes, *allVolumes[i].RegularVolume)
- } else {
- paginatedEcVolumes = append(paginatedEcVolumes, *allVolumes[i].EcVolume)
- }
- }
- // Convert maps to slices
- var dcList []string
- for dc := range dataCenters {
- dcList = append(dcList, dc)
- }
- sort.Strings(dcList)
- var diskTypeList []string
- for diskType := range diskTypes {
- diskTypeList = append(diskTypeList, diskType)
- }
- sort.Strings(diskTypeList)
- return &CollectionDetailsData{
- CollectionName: collectionName,
- RegularVolumes: paginatedRegularVolumes,
- EcVolumes: paginatedEcVolumes,
- TotalVolumes: len(regularVolumes),
- TotalEcVolumes: len(ecVolumes),
- TotalFiles: totalFiles,
- TotalSize: totalSize,
- DataCenters: dcList,
- DiskTypes: diskTypeList,
- LastUpdated: time.Now(),
- Page: page,
- PageSize: pageSize,
- TotalPages: totalPages,
- SortBy: sortBy,
- SortOrder: sortOrder,
- }, nil
- }
|