@@ -428,10 +428,6 @@ void TDeviceList::MarkDeviceAllocated(const TDiskId& diskId, const TDeviceId& id
428428 AllocatedDevices.emplace (id, diskId);
429429}
430430
431- // returns a list of racks sorted by preference and then by occupied space ASC
432- // then by free space DESC
433- // the nodes in each rack are sorted by occupied space ASC then by free space
434- // DESC
435431auto TDeviceList::SelectRacks (
436432 const TAllocationQuery& query,
437433 const TString& poolName) const -> TVector<TRack>
@@ -446,7 +442,6 @@ auto TDeviceList::SelectRacks(
446442 auto & rack = racks[currentRack];
447443 rack.Id = currentRack;
448444 rack.Nodes .push_back ({nodeId, 0 , 0 });
449- rack.Preferred = query.PreferredRacks .contains (currentRack);
450445 };
451446
452447 if (!query.NodeIds .empty ()) {
@@ -486,59 +481,74 @@ auto TDeviceList::SelectRacks(
486481
487482 TVector<TRack> result;
488483 result.reserve (racks.size ());
489- for (auto & r: racks) {
490- result.push_back (std::move (r.second ));
484+ for (auto & [_, r]: racks) {
485+ if (r.FreeSpace ) {
486+ result.push_back (std::move (r));
487+ }
491488 }
492489
493490 return result;
494491}
495492
493+ // Returns a ranked list of nodes. Sorting is performed in stages:
494+ // - Sort racks by preference, occupied space, free space
495+ // - Sort nodes within each rack by occupied space, free space
496+ // - Optionally apply custom NodeRankingFunc to all nodes (if set in query)
496497auto TDeviceList::RankNodes (
497498 const TAllocationQuery& query,
498- TVector<TRack> racks) const -> TVector<TNodeInfo >
499+ TVector<TRack> racks) const -> TVector<TNodeId >
499500{
500- Sort (
501- racks,
502- [](const TRack& l, const TRack& r)
503- {
504- return std::tie (r.Preferred , l.OccupiedSpace , r.FreeSpace , l.Id ) <
505- std::tie (l.Preferred , r.OccupiedSpace , l.FreeSpace , r.Id );
506- });
501+ // Sort racks by occupied space ASC then by free space DESC
502+ auto byRackSpace = [](const TRack& lhs, const TRack& rhs)
503+ {
504+ return std::tie (lhs.OccupiedSpace , rhs.FreeSpace , lhs.Id ) <
505+ std::tie (rhs.OccupiedSpace , lhs.FreeSpace , rhs.Id );
506+ };
507507
508- TVector<TNodeInfo> nodes;
508+ if (query.PreferredRacks ) {
509+ // Move preferred racks to the start of the list and sort each part
510+ auto it = std::partition (
511+ racks.begin (),
512+ racks.end (),
513+ [&](const TRack& rack) {
514+ return query.PreferredRacks .contains (rack.Id );
515+ });
516+ Sort (racks.begin (), it, byRackSpace);
517+ Sort (it, racks.end (), byRackSpace);
518+ } else {
519+ Sort (racks, byRackSpace);
520+ }
521+
522+ TVector<TNodeId> nodeIds;
509523 {
510524 size_t size = 0 ;
511525 for (const auto & rack: racks) {
512526 size += rack.Nodes .size ();
513527 }
514- nodes .reserve (size);
528+ nodeIds .reserve (size);
515529 }
516530
517- for (auto & rack: racks) {
531+ for (TRack& rack: racks) {
532+ // Sort rack's nodes by occupied space ASC then by free space DESC
518533 Sort (
519534 rack.Nodes ,
520- [](const TNodeInfo& l , const TNodeInfo& r )
535+ [](const TNodeInfo& lhs , const TNodeInfo& rhs )
521536 {
522- return std::tie (l .OccupiedSpace , r .FreeSpace ) <
523- std::tie (r .OccupiedSpace , l .FreeSpace );
537+ return std::tie (lhs .OccupiedSpace , rhs .FreeSpace ) <
538+ std::tie (rhs .OccupiedSpace , lhs .FreeSpace );
524539 });
525540
526- nodes.insert (
527- nodes.end (),
528- std::make_move_iterator (rack.Nodes .begin ()),
529- std::make_move_iterator (rack.Nodes .end ()));
541+ for (const TNodeInfo& node: rack.Nodes ) {
542+ nodeIds.push_back (node.NodeId );
543+ }
530544 }
531545
532- if (query.DownrankedNodeIds ) {
533- // move downranked nodes to the end of the list
534- std::stable_partition (
535- nodes.begin (),
536- nodes.end (),
537- [&](const TNodeInfo& node)
538- { return !query.DownrankedNodeIds .contains (node.NodeId ); });
546+ // Get the final order of nodes
547+ if (query.NodeRankingFunc ) {
548+ query.NodeRankingFunc (nodeIds);
539549 }
540550
541- return nodes ;
551+ return nodeIds ;
542552}
543553
544554TVector<TDeviceList::TDeviceRange> TDeviceList::CollectDevices (
@@ -552,8 +562,8 @@ TVector<TDeviceList::TDeviceRange> TDeviceList::CollectDevices(
552562 TVector<TDeviceRange> ranges;
553563 ui64 totalSize = query.GetTotalByteCount ();
554564
555- for (const auto & node : RankNodes (query, SelectRacks (query, poolName))) {
556- const auto * nodeDevices = NodeDevices.FindPtr (node. NodeId );
565+ for (ui32 nodeId : RankNodes (query, SelectRacks (query, poolName))) {
566+ const auto * nodeDevices = NodeDevices.FindPtr (nodeId );
557567 Y_ABORT_UNLESS (nodeDevices);
558568
559569 // finding free devices belonging to this node that match our
@@ -615,7 +625,7 @@ TVector<TDeviceList::TDeviceRange> TDeviceList::CollectDevices(
615625 }
616626
617627 if (deviceInfo.Range .first != it) {
618- ranges.emplace_back (node. NodeId , deviceInfo.Range .first , it);
628+ ranges.emplace_back (nodeId , deviceInfo.Range .first , it);
619629 }
620630
621631 if (totalSize == 0 ) {
0 commit comments