diff options
author | serg-belyakov <serg-belyakov@yandex-team.com> | 2022-09-01 10:20:54 +0300 |
---|---|---|
committer | serg-belyakov <serg-belyakov@yandex-team.com> | 2022-09-01 10:20:54 +0300 |
commit | 14291f2f6aea6fdce47fc32e6a278eb8970a4cbf (patch) | |
tree | c3a1380ba79d24c19f800cbee07ca7262f61912e | |
parent | 0e6a777dc2bc86bbf2f7e866a2cf3ae0539b34fd (diff) | |
download | ydb-14291f2f6aea6fdce47fc32e6a278eb8970a4cbf.tar.gz |
Chunk locking and API reworked,
Feature flags, remove lock from shared quota, chunk state diagram updated
Lock API works, GUI added
Chunks lock rework in progress
Flags now can be set with NPDisk::TStatusFlags object
SetSpaceColorFlag
24 files changed, 1094 insertions, 325 deletions
diff --git a/ydb/core/base/blobstorage.h b/ydb/core/base/blobstorage.h index d87a8f7297..e7011537c4 100644 --- a/ydb/core/base/blobstorage.h +++ b/ydb/core/base/blobstorage.h @@ -638,8 +638,8 @@ struct TEvBlobStorage { EvAnubisQuantumDone, EvAnubisCandidates, EvAnubisVGet, - EvChunksLock, - EvChunksUnlock, // 268 636 260 + EvChunkLock, + EvChunkUnlock, // 268 636 260 EvWhiteboardReportResult, EvHttpInfoResult, EvReadLogContinue, @@ -712,8 +712,8 @@ struct TEvBlobStorage { EvOsirisDone, EvSyncLogWriteDone, EvAnubisVGetResult, - EvChunksLockResult, - EvChunksUnlockResult, + EvChunkLockResult, + EvChunkUnlockResult, EvDelLogoBlobDataSyncLogResult, EvAddBulkSstResult, /// 268 636 702 EvAddBulkSstCommitted, diff --git a/ydb/core/blobstorage/base/blobstorage_vdiskid.h b/ydb/core/blobstorage/base/blobstorage_vdiskid.h index c8d5a818b1..5cd6a2e463 100644 --- a/ydb/core/blobstorage/base/blobstorage_vdiskid.h +++ b/ydb/core/blobstorage/base/blobstorage_vdiskid.h @@ -81,6 +81,8 @@ struct TVDiskID { TVDiskID VDiskIDFromVDiskID(const NKikimrBlobStorage::TVDiskID &x); void VDiskIDFromVDiskID(const TVDiskID &id, NKikimrBlobStorage::TVDiskID *proto); +// Takes a string in the same format as ToString output, sets isGenerationSet if second number is not '_' +TVDiskID VDiskIDFromString(TString str, bool* isGenerationSet = nullptr); //////////////////////////////////////////////////////////////////////////// // TVDiskIdShort -- topology info about VDisk, it avoids runtime info like diff --git a/ydb/core/blobstorage/docs/pdisk_chunk_state.graphml b/ydb/core/blobstorage/docs/pdisk_chunk_state.graphml index 16e22c88f0..28fc04ad3f 100644 --- a/ydb/core/blobstorage/docs/pdisk_chunk_state.graphml +++ b/ydb/core/blobstorage/docs/pdisk_chunk_state.graphml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd"> - <!--Created by yEd 3.20--> + <!--Created by yEd 3.22--> <key attr.name="Description" attr.type="string" for="graph" id="d0"/> <key for="port" id="d1" yfiles.type="portgraphics"/> <key for="port" id="d2" yfiles.type="portgeometry"/> @@ -17,10 +17,10 @@ <node id="n0"> <data key="d6"> <y:ShapeNode> - <y:Geometry height="66.60642868435133" width="149.0" x="270.8278580555715" y="32.23329615497357"/> + <y:Geometry height="66.60642868435133" width="216.7589040435288" x="262.8750699651887" y="32.23329615497357"/> <y:Fill color="#FFCC00" transparent="false"/> <y:BorderStyle color="#000000" type="line" width="1.0"/> - <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.029296875" x="58.9853515625" xml:space="preserve" y="24.236808092175664">FREE<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel> + <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="31.029296875" x="92.8648035842644" xml:space="preserve" y="24.236808092175664">FREE<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel> <y:Shape type="ellipse"/> </y:ShapeNode> </data> @@ -130,7 +130,7 @@ with req. in flight<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:Labe <node id="n10"> <data key="d6"> <y:ShapeNode> - <y:Geometry height="114.97089218898864" width="297.87834856212055" x="-45.750561560138465" y="-162.24229991112477"/> + <y:Geometry height="114.97089218898864" width="297.87834856212055" x="359.5910749100792" y="-277.3368951669519"/> <y:Fill hasColor="false" transparent="false"/> <y:BorderStyle hasColor="false" raised="false" type="line" width="1.0"/> <y:NodeLabel alignment="left" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="102.9296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="264.478515625" x="16.699916468560275" xml:space="preserve" y="6.0206023444943355">r — read @@ -147,7 +147,7 @@ kill checked — № kills in flight == 0<y:LabelModel><y:SmartNodeLabelModel di <node id="n11"> <data key="d6"> <y:ShapeNode> - <y:Geometry height="17.0" width="45.0" x="-45.750561560138465" y="-202.78920940360683"/> + <y:Geometry height="17.0" width="45.0" x="-80.62115563029045" y="-263.61090134163965"/> <y:Fill color="#FFCC00" transparent="false"/> <y:BorderStyle color="#000000" type="line" width="1.0"/> <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="e" textColor="#000000" verticalTextPosition="bottom" visible="true" width="93.244140625" x="49.0" xml:space="preserve" y="-0.56640625">Persistent state</y:NodeLabel> @@ -158,7 +158,7 @@ kill checked — № kills in flight == 0<y:LabelModel><y:SmartNodeLabelModel di <node id="n12"> <data key="d6"> <y:ShapeNode> - <y:Geometry height="17.0" width="45.0" x="118.24943843986154" y="-202.78920940360683"/> + <y:Geometry height="17.0" width="45.0" x="83.37884436970955" y="-263.61090134163965"/> <y:Fill color="#00CCFF" transparent="false"/> <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/> <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="e" textColor="#000000" verticalTextPosition="bottom" visible="true" width="224.76953125" x="49.0" xml:space="preserve" y="-0.56640625">Persistent state with requests in flight @@ -170,7 +170,7 @@ kill checked — № kills in flight == 0<y:LabelModel><y:SmartNodeLabelModel di <node id="n13"> <data key="d6"> <y:ShapeNode> - <y:Geometry height="17.0" width="45.0" x="-45.750561560138465" y="-179.24229991112477"/> + <y:Geometry height="17.0" width="45.0" x="-80.62115563029045" y="-240.0639918491576"/> <y:Fill color="#FFFF99" transparent="false"/> <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/> <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="e" textColor="#000000" verticalTextPosition="bottom" visible="true" width="91.609375" x="49.0" xml:space="preserve" y="-0.56640625">Temporal state</y:NodeLabel> @@ -181,7 +181,7 @@ kill checked — № kills in flight == 0<y:LabelModel><y:SmartNodeLabelModel di <node id="n14"> <data key="d6"> <y:ShapeNode> - <y:Geometry height="17.0" width="45.0" x="118.24943843986154" y="-179.24229991112477"/> + <y:Geometry height="17.0" width="45.0" x="83.37884436970955" y="-240.0639918491576"/> <y:Fill color="#CCFFFF" transparent="false"/> <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/> <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="sides" modelPosition="e" textColor="#000000" verticalTextPosition="bottom" visible="true" width="223.134765625" x="49.0" xml:space="preserve" y="-0.56640625">Temporal state with requests in flight @@ -301,13 +301,25 @@ on kill<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:Mo </y:ShapeNode> </data> </node> + <node id="n24"> + <data key="d5"/> + <data key="d6"> + <y:ShapeNode> + <y:Geometry height="49.60856260758885" width="161.73798814537497" x="54.06605420626795" y="-60.93211114438037"/> + <y:Fill color="#FFFF99" transparent="false"/> + <y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/> + <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="51.349609375" x="55.194189385187485" xml:space="preserve" y="15.737875053794426">LOCKED<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:ModelParameter><y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/></y:ModelParameter></y:NodeLabel> + <y:Shape type="ellipse"/> + </y:ShapeNode> + </data> + </node> <edge id="e0" source="n0" target="n1"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-3.266600149779511" sy="30.51955177122861" tx="33.04606813765801" ty="-25.862235383418323"/> + <y:Path sx="-4.7521118685545884" sy="30.51955177122861" tx="33.04606813765801" ty="-25.862235383418323"/> <y:LineStyle color="#000000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-24.342703019428484" anchorY="23.117720616015703" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.6509328382247169" upY="0.7591353239842779" verticalTextPosition="bottom" visible="true" width="46.205078125" x="-59.418609971569225" xml:space="preserve" y="23.117720616015703">reserve<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.770418224707337" distanceToCenter="true" position="left" ratio="0.6881208058219688" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="-33.64783085811075" anchorY="25.31692156878441" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.5684023361311652" upY="0.8227507424977712" verticalTextPosition="bottom" visible="true" width="46.205078125" x="-71.66309319262203" xml:space="preserve" y="25.31692156878441">reserve<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.770418224707337" distanceToCenter="true" position="left" ratio="0.6881208058219688" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -326,10 +338,10 @@ on kill<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:Mo <edge id="e2" source="n0" target="n3"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="32.70706277112947" sy="-29.95737068295808" tx="-42.122804543122015" ty="21.999721690874836"/> + <y:Path sx="47.58085289095922" sy="-29.95737068295808" tx="-42.122804543122015" ty="21.999721690874836"/> <y:LineStyle color="#000000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="34.18409800185162" anchorY="-28.177011227718623" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="-0.6190551959484245" upY="-0.7853474800171308" verticalTextPosition="bottom" visible="true" width="71.001953125" x="22.95888620656808" xml:space="preserve" y="-86.37169783473448">log allocate<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="10.033313003993115" distanceToCenter="true" position="left" ratio="0.8551926321358523" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="12.551123028002337" anchorY="-16.561158546091498" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="-0.7680127111740203" upY="-0.6404345989054081" verticalTextPosition="bottom" visible="true" width="71.001953125" x="-1.3751074613328278" xml:space="preserve" y="-82.70444156473792">log allocate<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="10.033313003993115" distanceToCenter="true" position="left" ratio="0.8551926321358523" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -349,7 +361,7 @@ on kill<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:Mo <edge id="e4" source="n5" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-112.65426207463007" sy="-6.6171167533117625" tx="-58.74680984228439" ty="-20.460974229421915"> + <y:Path sx="-112.65426207463007" sy="-6.6171167533117625" tx="-108.3794520217644" ty="0.0"> <y:Point x="-67.0" y="80.0"/> <y:Point x="-22.0" y="44.0"/> </y:Path> @@ -375,10 +387,12 @@ on kill<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:Mo <edge id="e6" source="n4" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="94.75529115096823" sy="-18.75744075972699" tx="-74.5" ty="0.0"/> + <y:Path sx="94.75529115096823" sy="-18.75744075972699" tx="-100.78769016986814" ty="12.218120447170946"> + <y:Point x="250.62556766372967" y="77.75463094432018"/> + </y:Path> <y:LineStyle color="#000000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="34.389930138957396" anchorY="-2.8939179108398605" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" rotationAngle="0.3874289095401764" textColor="#000000" upX="-0.10808080353406267" upY="-0.9941421125309154" verticalTextPosition="bottom" visible="true" width="72.419921875" x="32.37723955609026" xml:space="preserve" y="-29.247199375435827">delete done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="8.471119764567563" distanceToCenter="true" position="left" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="26.680614591938422" anchorY="0.020216090176518264" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" rotationAngle="0.3874289095401764" textColor="#000000" upX="-0.023732992077214778" upY="-0.9997183328753468" verticalTextPosition="bottom" visible="true" width="72.419921875" x="26.238656648481644" xml:space="preserve" y="-20.318241978882778">delete done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="-0.023735220596176276" distance="10.149012846192845" distanceToCenter="true" position="left" ratio="0.10174658742324738" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -389,7 +403,7 @@ on kill<y:LabelModel><y:SmartNodeLabelModel distance="4.0"/></y:LabelModel><y:Mo <y:Path sx="0.0" sy="0.0" tx="0.0" ty="-33.30321434217566"/> <y:LineStyle color="#000000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-15.241849091136089" anchorY="8.711330163320127" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.9935261648072331" upY="-0.1136035203830875" verticalTextPosition="bottom" visible="true" width="44.201171875" x="-15.241849091136089" xml:space="preserve" y="5.045841575959569">сut log + <y:EdgeLabel alignment="center" anchorX="-11.440907277162523" anchorY="16.113047650241683" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.9435322867020511" upY="-0.3312805819102568" verticalTextPosition="bottom" visible="true" width="44.201171875" x="-11.440907277162523" xml:space="preserve" y="5.4240726245435535">сut log <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.91080997813034" distanceToCenter="true" position="center" ratio="0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> @@ -466,10 +480,10 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e14" source="n19" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-84.0" sy="0.0" tx="39.67214194442852" ty="-15.536510497149237"/> + <y:Path sx="-84.0" sy="0.0" tx="57.71335576465524" ty="-15.536510497149237"/> <y:LineStyle color="#000000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-12.688845673205378" anchorY="-13.570694958210325" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.23829896866447176" upY="0.9711918458952634" verticalTextPosition="bottom" visible="true" width="72.89453125" x="-83.48342003356284" xml:space="preserve" y="-13.570694958210325">kill checked + <y:EdgeLabel alignment="center" anchorX="-13.346394017437433" anchorY="-13.200982229484396" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="0.258678190955444" upY="0.9659635570372305" verticalTextPosition="bottom" visible="true" width="72.89453125" x="-83.75985471224898" xml:space="preserve" y="-13.200982229484396">kill checked <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="-0.0015521447859940807" distance="45.32133572498151" distanceToCenter="true" position="center" ratio="1.5241256481795973E-15" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> @@ -478,12 +492,12 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e15" source="n0" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-14.327858055571483" sy="-21.536510497149237" tx="-49.32785805557148" ty="-11.536510497149237"> + <y:Path sx="-20.84356247930819" sy="-21.536510497149237" tx="-71.76008356335856" ty="-11.536510497149237"> <y:Point x="308.8278580555715" y="20.042778699409723"/> </y:Path> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-58.28154998501168" xml:space="preserve" y="-29.072558409519985">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="0.851185318054408" distanceToCenter="true" position="left" ratio="11.065409134708744" segment="-2"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-77.43657732322367" xml:space="preserve" y="-26.493800250551928">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="0.851185318054408" distanceToCenter="true" position="left" ratio="11.065409134708744" segment="-2"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -491,10 +505,10 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e16" source="n3" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-60.03932684314634" sy="7.456239096264476" tx="12.98890593117062" ty="-32.81242430255824"/> + <y:Path sx="-60.03932684314634" sy="7.456239096264476" tx="18.895711505805597" ty="-32.81242430255824"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-56.50374877298367" anchorY="23.59199226484818" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="0.6577425399155834" upY="0.753242823520674" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-90.78218195273308" xml:space="preserve" y="23.59199226484818">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.328015368693165" distanceToCenter="true" position="right" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="-45.68234671896829" anchorY="24.07507892571121" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="0.7643603441854456" upY="0.644789317712931" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-75.02529809145128" xml:space="preserve" y="24.07507892571121">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.328015368693165" distanceToCenter="true" position="right" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -515,10 +529,10 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e18" source="n1" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="20.765200607281315" sy="-28.449174732740687" tx="-23.584504627711578" ty="31.618739264026544"/> + <y:Path sx="20.765200607281315" sy="-28.449174732740687" tx="-34.309740775250276" ty="31.618739264026544"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="14.921208160972867" anchorY="-15.51563064408441" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.6655841906681687" upY="-0.7463227754347304" verticalTextPosition="bottom" visible="true" width="45.5078125" x="2.852294828622716" xml:space="preserve" y="-59.337842147413255">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.714745422657094" distanceToCenter="true" position="left" ratio="0.342725244313297" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="18.301066197345023" anchorY="-16.112009102077963" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.6085391549750586" upY="-0.7935238476959855" verticalTextPosition="bottom" visible="true" width="45.5078125" x="7.266539801273842" xml:space="preserve" y="-58.194114010141234">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.714745422657094" distanceToCenter="true" position="left" ratio="0.342725244313297" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -537,10 +551,10 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e20" source="n4" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="121.43917428106026" sy="0.0" tx="-61.28642551023529" ty="18.92692580335762"/> + <y:Path sx="121.43917428106026" sy="0.0" tx="-56.9211909301568" ty="27.77174474197173"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="21.339804436673944" anchorY="-3.747454867707347" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" rotationAngle="0.1801728457212448" textColor="#FF0000" upX="-0.12091589143554073" upY="-0.992662756024597" verticalTextPosition="bottom" visible="true" width="45.5078125" x="19.1299665347919" xml:space="preserve" y="-27.398672767417132">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="1.139638740070015" distanceToCenter="false" position="left" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="16.324849407100828" anchorY="-1.5447826621072238" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" rotationAngle="0.1801728457212448" textColor="#FF0000" upX="-0.0247886574873109" upY="-0.9996927140176509" verticalTextPosition="bottom" visible="true" width="45.5078125" x="15.871816193667225" xml:space="preserve" y="-20.944479122832597">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="1.139638740070015" distanceToCenter="false" position="left" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -575,10 +589,10 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e23" source="n9" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-38.077296542883346" sy="-25.210897068395468" tx="9.704303390119492" ty="24.850110352812152"/> + <y:Path sx="-38.077296542883346" sy="-25.210897068395468" tx="14.117410519115449" ty="24.850110352812152"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-0.13836735026870883" anchorY="-32.00833866542118" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.8215403633406544" upY="0.5701503585915785" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-40.98150033549999" xml:space="preserve" y="-69.39484348150955">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="9.069496224652644" distanceToCenter="true" position="right" ratio="0.5454974242562394" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="9.325317859491179" anchorY="-27.236869195112888" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.9388123832974636" upY="0.3444289606977557" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-23.372199622523198" xml:space="preserve" y="-69.96016710689199">restart<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="9.069496224652644" distanceToCenter="true" position="right" ratio="0.5454974242562394" segment="-1"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -608,7 +622,7 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e26" source="n7" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-23.11331187254541" sy="-28.667399723622253" tx="69.36407250951441" ty="12.145183315960296"> + <y:Path sx="-23.11331187254541" sy="-28.667399723622253" tx="100.90792172589396" ty="12.145183315960296"> <y:Point x="754.0" y="9.0"/> </y:Path> <y:LineStyle color="#FF0000" type="line" width="1.0"/> @@ -734,10 +748,10 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e36" source="n17" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="0.0" sy="0.0" tx="14.672141944428517" ty="25.463489502850763"/> + <y:Path sx="0.0" sy="0.0" tx="21.344412133190694" ty="25.463489502850763"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-38.28153394842229" anchorY="-16.773801256745173" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.016683072883772274" upY="0.9998608278551344" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-84.321302802064" xml:space="preserve" y="-17.533011409463715">restart + <y:EdgeLabel alignment="center" anchorX="-8.466449243049283" anchorY="-16.29230740949714" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.01850898620943693" upY="0.9998286940418838" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-54.56366999179106" xml:space="preserve" y="-17.134610883481283">restart <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> @@ -774,14 +788,15 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <data key="d10"> <y:PolyLineEdge> <y:Path sx="0.0" sy="0.0" tx="-65.46734025726944" ty="-16.546552357831843"> - <y:Point x="183.0" y="5.0"/> - <y:Point x="298.0" y="-129.0"/> + <y:Point x="-87.59816398472617" y="203.04648233664744"/> + <y:Point x="-87.59816398472617" y="63.32634010100176"/> + <y:Point x="95.0342281563768" y="-120.18994360238298"/> <y:Point x="551.0" y="-129.0"/> </y:Path> <y:LineStyle color="#800000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="15.170497110918774" anchorY="-8.923609179765151" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#800000" upX="-0.9927550037849064" upY="0.12015615864378441" verticalTextPosition="bottom" visible="true" width="65.640625" x="-24.748488909055762" xml:space="preserve" y="-74.08866810008378">kill owner - <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="false" position="center" ratio="-0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:EdgeLabel alignment="center" anchorX="-5.05823790275565" anchorY="-16.23479016096985" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#800000" upX="-0.019547548840377255" upY="0.9998089284129908" verticalTextPosition="bottom" visible="true" width="65.640625" x="-71.31703472491742" xml:space="preserve" y="-17.51790348407024">kill owner + <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="false" position="center" ratio="-2.8421709430404007E-14" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> @@ -839,17 +854,16 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e44" source="n18" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-68.7123163546596" sy="-20.921820629983927" tx="32.88429240564517" ty="29.90209341103973"/> + <y:Path sx="-68.7123163546596" sy="-20.921820629983927" tx="47.838679074460295" ty="29.90209341103973"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-32.21079350956222" anchorY="-29.423948093795076" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.3536121530440552" upY="0.9353921344652988" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-86.18796050434591" xml:space="preserve" y="-45.51606365224524">restart + <y:EdgeLabel alignment="center" anchorX="-32.215737357218586" anchorY="-32.358228536422445" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="-0.4136763520163348" upY="0.910424008790661" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-86.9946684902894" xml:space="preserve" y="-51.18373439966581">restart <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> </edge> <edge id="e45" source="n7" target="n19"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"> @@ -865,10 +879,9 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e46" source="n19" target="n0"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="0.0" sy="0.0" tx="70.06277181750886" ty="-11.308632626847142"> + <y:Path sx="0.0" sy="0.0" tx="101.9243599558057" ty="-11.308632626847142"> <y:Point x="738.5" y="-16.5"/> </y:Path> <y:LineStyle color="#FF0000" type="line" width="1.0"/> @@ -880,7 +893,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e47" source="n20" target="n19"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="68.22341079099817" sy="-14.840091304253292" tx="-67.51814692901598" ty="-17.840091304253292"/> @@ -893,7 +905,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e48" source="n15" target="n21"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="148.93917428106033" sy="0.0" tx="0.0" ty="0.0"/> @@ -906,7 +917,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e49" source="n21" target="n19"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="94.35164449958506" sy="-21.562300964265944" tx="63.540205984084196" ty="19.606197365102012"> @@ -936,7 +946,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e51" source="n17" target="n22"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"> @@ -952,7 +961,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e52" source="n21" target="n22"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="57.013018778578044" sy="-27.20830256035157" tx="91.93418296074992" ty="22.1308088577278"/> @@ -965,7 +973,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e53" source="n21" target="n2"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="20.72578420112997" sy="29.65314525408712" tx="25.80840170413086" ty="27.544306782716205"> @@ -983,17 +990,16 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl <edge id="e54" source="n20" target="n0"> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="-65.67422847420744" sy="16.435470222136132" tx="44.05397482574898" ty="-26.849895640639183"/> + <y:Path sx="-65.67422847420744" sy="16.435470222136132" tx="64.08786108718493" ty="-26.849895640639183"/> <y:LineStyle color="#FF0000" type="line" width="1.0"/> <y:Arrows source="none" target="standard"/> - <y:EdgeLabel alignment="center" anchorX="-30.395815728128923" anchorY="-6.226655310221076" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" rotationAngle="0.06348316371440887" textColor="#FF0000" upX="0.3897029174683606" upY="0.9209406257281998" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-72.33870694016943" xml:space="preserve" y="-6.226655310221076">restart + <y:EdgeLabel alignment="center" anchorX="-32.426262988088865" anchorY="-3.3194147454848064" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" rotationAngle="0.06348316371440887" textColor="#FF0000" upX="0.45253388474936923" upY="0.8917472080997196" verticalTextPosition="bottom" visible="true" width="45.5078125" x="-73.03958277555375" xml:space="preserve" y="-3.3194147454848064">restart <y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="true" defaultAngle="0.0" defaultDistance="10.0"/></y:LabelModel><y:ModelParameter><y:SmartEdgeLabelModelParameter angle="6.253782031152642" distance="81.32920258771165" distanceToCenter="false" position="center" ratio="0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> <y:BendStyle smoothed="false"/> </y:PolyLineEdge> </data> </edge> <edge id="e55" source="n22" target="n19"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="36.13203517379452" sy="-28.941759204047173" tx="30.744556978383116" ty="27.924597339556847"/> @@ -1034,7 +1040,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e58" source="n23" target="n2"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="-51.09322234633055" sy="21.862249731766667" tx="4.24623156558755" ty="29.92153361798944"> @@ -1050,7 +1055,6 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e59" source="n23" target="n19"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> <y:Path sx="32.854097267713314" sy="-26.941783853259437" tx="42.998798444398744" ty="1.4210854715202004E-14"> @@ -1066,10 +1070,9 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </data> </edge> <edge id="e60" source="n22" target="n0"> - <data key="d9"/> <data key="d10"> <y:PolyLineEdge> - <y:Path sx="10.539312957498396" sy="-29.90016379454329" tx="74.5" ty="0.0"> + <y:Path sx="10.539312957498396" sy="-29.90016379454329" tx="108.37945202176434" ty="0.0"> <y:Point x="822.212015155839" y="-21.332808843623777"/> </y:Path> <y:LineStyle color="#FF0000" type="line" width="1.0"/> @@ -1080,6 +1083,42 @@ done<y:LabelModel><y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngl </y:PolyLineEdge> </data> </edge> + <edge id="e61" source="n0" target="n24"> + <data key="d9"/> + <data key="d10"> + <y:PolyLineEdge> + <y:Path sx="-100.68439605476857" sy="-12.303481947299332" tx="-55.47603759097372" ty="19.20437443001407"/> + <y:LineStyle color="#000000" type="line" width="1.0"/> + <y:Arrows source="none" target="standard"/> + <y:EdgeLabel alignment="center" anchorX="-107.26699332182693" anchorY="-38.31223346840882" configuration="AutoFlippingLabel" distance="1.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" upX="-0.3446114449445511" upY="0.9387454138440458" verticalTextPosition="bottom" visible="true" width="28.0" x="-139.80063962599382" xml:space="preserve" y="-47.96135392685625">lock<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="1.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.7499999999999996" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:BendStyle smoothed="false"/> + </y:PolyLineEdge> + </data> + </edge> + <edge id="e62" source="n24" target="n0"> + <data key="d9"/> + <data key="d10"> + <y:PolyLineEdge> + <y:Path sx="13.40292093783387" sy="24.470086197646374" tx="-85.82933288697728" ty="-20.330155132444112"/> + <y:LineStyle color="#FF0000" type="line" width="1.0"/> + <y:Arrows source="none" target="standard"/> + <y:EdgeLabel alignment="center" anchorX="37.037046276193564" anchorY="14.28043451140415" configuration="AutoFlippingLabel" distance="1.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#FF0000" upX="0.3831475825736732" upY="-0.9236871385745015" verticalTextPosition="bottom" visible="true" width="45.5078125" x="37.037046276193564" xml:space="preserve" y="-2.4686111810288">restart<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="1.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:BendStyle smoothed="false"/> + </y:PolyLineEdge> + </data> + </edge> + <edge id="e63" source="n24" target="n0"> + <data key="d9"/> + <data key="d10"> + <y:PolyLineEdge> + <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/> + <y:LineStyle color="#800000" type="line" width="1.0"/> + <y:Arrows source="none" target="standard"/> + <y:EdgeLabel alignment="center" anchorX="31.97628843007368" anchorY="11.578938151897725" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="bold" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#800000" upX="0.3951818215077674" upY="-0.9186029218056098" verticalTextPosition="bottom" visible="true" width="65.640625" x="31.97628843007368" xml:space="preserve" y="-5.077916391155556">kill owner<y:LabelModel><y:RotatedSliderEdgeLabelModel angle="0.0" autoRotationEnabled="true" distance="2.0" distanceRelativeToEdge="true" mode="side_slider"/></y:LabelModel><y:ModelParameter><y:RotatedSliderEdgeLabelModelParameter invertingSign="true" ratio="0.0" segment="0"/></y:ModelParameter><y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel> + <y:BendStyle smoothed="false"/> + </y:PolyLineEdge> + </data> + </edge> </graph> <data key="d7"> <y:Resources/> diff --git a/ydb/core/blobstorage/dsproxy/mock/model.h b/ydb/core/blobstorage/dsproxy/mock/model.h index 5568640311..79c1cd52c1 100644 --- a/ydb/core/blobstorage/dsproxy/mock/model.h +++ b/ydb/core/blobstorage/dsproxy/mock/model.h @@ -48,6 +48,8 @@ namespace NFake { THashMap<std::pair<TTabletId, TChannel>, TBarrier> Barriers; THashMap<std::pair<TTabletId, TChannel>, TBarrier> HardBarriers; TMap<TLogoBlobID, TBlob> Blobs; + // By default only NKikimrBlobStorage::StatusIsValid is set + TStorageStatusFlags StorageStatusFlags = TStorageStatusFlags(NKikimrBlobStorage::StatusIsValid); public: // BS events interface : Handle(event) -> event TEvBlobStorage::TEvPutResult* Handle(TEvBlobStorage::TEvPut *msg) { @@ -319,7 +321,45 @@ namespace NFake { public: // Non-event model interaction methods TStorageStatusFlags GetStorageStatusFlags() const noexcept { - return TStorageStatusFlags(NKikimrBlobStorage::StatusIsValid); + return StorageStatusFlags; + } + + void SetStorageStatusFlagsByColor(NKikimrBlobStorage::EStatusFlags color) { + // Only changes StorageStatusFlags if given EStatusFlags value is color + // Also raises all color flags, that are 'greener' than given + + ui32 newFlags = NKikimrBlobStorage::StatusIsValid; + switch (color) { + case NKikimrBlobStorage::StatusDiskSpaceBlack: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceBlack); + [[fallthrough]]; + case NKikimrBlobStorage::StatusDiskSpaceRed: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceRed); + [[fallthrough]]; + case NKikimrBlobStorage::StatusDiskSpaceOrange: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceOrange); + [[fallthrough]]; + case NKikimrBlobStorage::StatusDiskSpaceLightOrange: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceLightOrange); + [[fallthrough]]; + case NKikimrBlobStorage::StatusDiskSpaceYellowStop: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceYellowStop); + [[fallthrough]]; + case NKikimrBlobStorage::StatusDiskSpaceLightYellowMove: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceLightYellowMove); + [[fallthrough]]; + case NKikimrBlobStorage::StatusDiskSpaceCyan: + newFlags |= ui32(NKikimrBlobStorage::StatusDiskSpaceCyan); + break; + default: + newFlags = 0; + break; + } + StorageStatusFlags.Merge(newFlags); + } + + void SetStorageStatusFlags(TStorageStatusFlags flags) { + StorageStatusFlags = flags; } const TMap<TLogoBlobID, TBlob>& AllMyBlobs() const noexcept { diff --git a/ydb/core/blobstorage/groupinfo/blobstorage_groupinfo.cpp b/ydb/core/blobstorage/groupinfo/blobstorage_groupinfo.cpp index 928dbfd770..e663567105 100644 --- a/ydb/core/blobstorage/groupinfo/blobstorage_groupinfo.cpp +++ b/ydb/core/blobstorage/groupinfo/blobstorage_groupinfo.cpp @@ -17,6 +17,9 @@ #include <util/stream/input.h> #include <util/random/fast.h> #include <util/system/unaligned_mem.h> +#include <util/string/vector.h> +#include <util/string/type.h> +#include <util/string/cast.h> namespace NKikimr { @@ -919,6 +922,42 @@ void VDiskIDFromVDiskID(const TVDiskID &id, NKikimrBlobStorage::TVDiskID *proto) proto->SetVDisk(id.VDisk); } +TVDiskID VDiskIDFromString(TString str, bool* isGenerationSet) { + if (str[0] != '[' || str.back() != ']') { + return TVDiskID::InvalidId; + } + str.pop_back(); + str.erase(str.begin()); + TVector<TString> parts = SplitString(str, ":"); + if (parts.size() != 5) { + return TVDiskID::InvalidId; + } + + ui32 groupGeneration = 0; + + if (!IsHexNumber(parts[0]) || !IsNumber(parts[2]) || !IsNumber(parts[3]) || !IsNumber(parts[4]) + || !(IsNumber(parts[1]) || parts[1] == "_")) { + return TVDiskID::InvalidId; + } + + if (parts[1] == "_") { + if (isGenerationSet) { + *isGenerationSet = false; + } + } else { + if (isGenerationSet) { + *isGenerationSet = true; + } + groupGeneration = IntFromString<ui32, 10>(parts[1]); + } + + return TVDiskID(IntFromString<ui32, 16>(parts[0]), + groupGeneration, + IntFromString<ui8, 10>(parts[2]), + IntFromString<ui8, 10>(parts[3]), + IntFromString<ui8, 10>(parts[4])); +} + TFailDomain::TLevelIds::TLevelIds() { } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h index 44edf4be99..765a05d478 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk.h @@ -475,54 +475,116 @@ struct TEvReadLogResult : public TEventLocal<TEvReadLogResult, TEvBlobStorage::E } }; //////////////////////////////////////////////////////////////////////////////// -// Lock chucks specified by range or by count +// Lock chucks specified by color or by count //////////////////////////////////////////////////////////////////////////////// -struct TEvChunksLock : public TEventLocal<TEvChunksLock, TEvBlobStorage::EvChunksLock> { - bool LockByRange; - TChunkIdx Begin; - TChunkIdx End; +struct TEvChunkLock : public TEventLocal<TEvChunkLock, TEvBlobStorage::EvChunkLock> { + enum ELockFrom { + LOG, + PERSONAL_QUOTA, + COUNT + }; + + static TString ELockFrom_Name(const ELockFrom& from) { + switch (from) { + case LOG: return "log"; + case PERSONAL_QUOTA: return "personal_quota"; + default: return "unknown"; + } + } + + static ELockFrom LockFromByName(const TString& name) { + for (ELockFrom from : {ELockFrom::LOG, ELockFrom::PERSONAL_QUOTA}) { + if (name == ELockFrom_Name(from)) { + return from; + } + } + return ELockFrom::COUNT; // Wrong name + } + + ELockFrom LockFrom; + bool ByVDiskId = true; + TOwner Owner = 0; + TVDiskID VDiskId = TVDiskID::InvalidId; + bool IsGenerationSet = true; ui32 Count; + NKikimrBlobStorage::TPDiskSpaceColor::E Color; - TEvChunksLock(bool lockByRange, TChunkIdx begin, TChunkIdx end, ui32 count) - : LockByRange(lockByRange) - , Begin(begin) - , End(end) + TEvChunkLock(ELockFrom from, ui32 count, NKikimrBlobStorage::TPDiskSpaceColor::E color) + : LockFrom(from) , Count(count) - {} + , Color(color) + { + Y_VERIFY_DEBUG(from != ELockFrom::PERSONAL_QUOTA); + } + + TEvChunkLock(ELockFrom from, TOwner owner, ui32 count, NKikimrBlobStorage::TPDiskSpaceColor::E color) + : LockFrom(from) + , ByVDiskId(false) + , Owner(owner) + , Count(count) + , Color(color) + { + Y_VERIFY_DEBUG(from == ELockFrom::PERSONAL_QUOTA); + } + + TEvChunkLock(ELockFrom from, TVDiskID vdiskId, bool isGenerationSet, ui32 count, NKikimrBlobStorage::TPDiskSpaceColor::E color) + : LockFrom(from) + , ByVDiskId(true) + , VDiskId(vdiskId) + , IsGenerationSet(isGenerationSet) + , Count(count) + , Color(color) + { + Y_VERIFY_DEBUG(from == ELockFrom::PERSONAL_QUOTA); + } TString ToString() const { return ToString(*this); } - static TString ToString(const TEvChunksLock &record) { + static TString ToString(const TEvChunkLock &record) { TStringStream str; - str << "{EvChunksLock LockByRange# " << (ui32)record.LockByRange; - str << " Begin# " << record.Begin; - str << " End# " << record.End; + + str << "{EvChunkLock LockFrom# " << ELockFrom_Name(record.LockFrom); + + if (record.LockFrom == ELockFrom::PERSONAL_QUOTA) { + if (record.ByVDiskId) { + if (record.IsGenerationSet) { + str << " VDiskId# " << record.VDiskId.ToString(); + } else { + str << " VDiskId# " << record.VDiskId.ToStringWOGeneration(); + } + } else { + str << " Owner# " << record.Owner; + } + } str << " Count# " << record.Count; str << "}"; return str.Str(); } }; -struct TEvChunksLockResult : public TEventLocal<TEvChunksLockResult, TEvBlobStorage::EvChunksLockResult> { +struct TEvChunkLockResult : public TEventLocal<TEvChunkLockResult, TEvBlobStorage::EvChunkLockResult> { NKikimrProto::EReplyStatus Status; TVector<TChunkIdx> LockedChunks; ui32 AvailableChunksCount; + TString ErrorReason; - TEvChunksLockResult(NKikimrProto::EReplyStatus status, TVector<TChunkIdx> locked, ui32 availableChunksCount) + TEvChunkLockResult(NKikimrProto::EReplyStatus status, TVector<TChunkIdx> locked, ui32 availableChunksCount, + TString errorReason = TString()) : Status(status) , LockedChunks(locked) , AvailableChunksCount(availableChunksCount) + , ErrorReason(errorReason) {} TString ToString() const { return ToString(*this); } - static TString ToString(const TEvChunksLockResult &record) { + static TString ToString(const TEvChunkLockResult &record) { TStringStream str; - str << "{EvChunksLockResult Status# " << NKikimrProto::EReplyStatus_Name(record.Status).data(); + str << "{EvChunkLockResult Status# " << NKikimrProto::EReplyStatus_Name(record.Status).data(); str << " LockedChunks# {"; for (ui64 i = 0; i < record.LockedChunks.size(); ++i) { if (i) { @@ -531,6 +593,9 @@ struct TEvChunksLockResult : public TEventLocal<TEvChunksLockResult, TEvBlobStor str << record.LockedChunks[i]; } str << "}"; + if (!record.ErrorReason.empty()) { + str << " ErrorReason# " << record.ErrorReason; + } str << "}"; return str.Str(); } @@ -538,40 +603,82 @@ struct TEvChunksLockResult : public TEventLocal<TEvChunksLockResult, TEvBlobStor //////////////////////////////////////////////////////////////////////////////// // Unlock all previously locked chunks //////////////////////////////////////////////////////////////////////////////// -struct TEvChunksUnlock : public TEventLocal<TEvChunksUnlock, TEvBlobStorage::EvChunksUnlock> { +struct TEvChunkUnlock : public TEventLocal<TEvChunkUnlock, TEvBlobStorage::EvChunkUnlock> { + TEvChunkLock::ELockFrom LockFrom; + bool ByVDiskId = true; + TOwner Owner = 0; + TVDiskID VDiskId = TVDiskID::InvalidId; + bool IsGenerationSet = true; + + TEvChunkUnlock(TEvChunkLock::ELockFrom lockFrom) + : LockFrom(lockFrom) + { + Y_VERIFY_DEBUG(LockFrom != TEvChunkLock::ELockFrom::PERSONAL_QUOTA); + } - TEvChunksUnlock() - {} + TEvChunkUnlock(TEvChunkLock::ELockFrom lockFrom, TOwner owner) + : LockFrom(lockFrom) + , ByVDiskId(false) + , Owner(owner) + { + Y_VERIFY_DEBUG(LockFrom == TEvChunkLock::ELockFrom::PERSONAL_QUOTA); + } + + TEvChunkUnlock(TEvChunkLock::ELockFrom lockFrom, TVDiskID vdiskId, bool isGenerationSet) + : LockFrom(lockFrom) + , ByVDiskId(true) + , VDiskId(vdiskId) + , IsGenerationSet(isGenerationSet) + { + Y_VERIFY_DEBUG(LockFrom == TEvChunkLock::ELockFrom::PERSONAL_QUOTA); + } TString ToString() const { return ToString(*this); } - static TString ToString(const TEvChunksUnlock &record) { + static TString ToString(const TEvChunkUnlock &record) { Y_UNUSED(record); TStringStream str; - str << "{EvChunksUnlock}"; + str << "{EvChunkUnlock"; + str << "{EvChunkLock LockFrom# " << TEvChunkLock::ELockFrom_Name(record.LockFrom); + if (record.Owner) { + str << " Owner# " << record.Owner; + } + if (record.ByVDiskId) { + if (record.IsGenerationSet) { + str << " VDiskId# " << record.VDiskId.ToString(); + } else { + str << " VDiskId# " << record.VDiskId.ToStringWOGeneration(); + } + } + str << "}"; return str.Str(); } }; -struct TEvChunksUnlockResult : public TEventLocal<TEvChunksUnlockResult, TEvBlobStorage::EvChunksUnlockResult> { +struct TEvChunkUnlockResult : public TEventLocal<TEvChunkUnlockResult, TEvBlobStorage::EvChunkUnlockResult> { NKikimrProto::EReplyStatus Status; ui32 UnlockedChunks; + TString ErrorReason; - TEvChunksUnlockResult(NKikimrProto::EReplyStatus status, ui32 unlocked) + TEvChunkUnlockResult(NKikimrProto::EReplyStatus status, ui32 unlocked, TString errorReason = "") : Status(status) , UnlockedChunks(unlocked) + , ErrorReason(errorReason) {} TString ToString() const { return ToString(*this); } - static TString ToString(const TEvChunksUnlockResult &record) { + static TString ToString(const TEvChunkUnlockResult &record) { TStringStream str; - str << "{EvChunksUnlockResult Status# " << NKikimrProto::EReplyStatus_Name(record.Status).data(); + str << "{EvChunkUnlockResult Status# " << NKikimrProto::EReplyStatus_Name(record.Status).data(); str << " UnlockedChunks# " << record.UnlockedChunks; + if (!record.ErrorReason.empty()) { + str << " ErrorReason# " << record.ErrorReason; + } str << "}"; return str.Str(); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp index f3951b855a..220748cd18 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_actor.cpp @@ -738,13 +738,13 @@ public: PDisk->InputRequest(request); } - void Handle(NPDisk::TEvChunksLock::TPtr &ev) { - auto* request = PDisk->ReqCreator.CreateFromEv<TChunksLock>(*ev->Get(), ev->Sender); + void Handle(NPDisk::TEvChunkLock::TPtr &ev) { + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(*ev->Get(), ev->Sender); PDisk->InputRequest(request); } - void Handle(NPDisk::TEvChunksUnlock::TPtr &ev) { - auto* request = PDisk->ReqCreator.CreateFromEv<TChunksUnlock>(*ev->Get(), ev->Sender); + void Handle(NPDisk::TEvChunkUnlock::TPtr &ev) { + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkUnlock>(*ev->Get(), ev->Sender); PDisk->InputRequest(request); } @@ -901,22 +901,77 @@ public: void Handle(NMon::TEvHttpInfo::TPtr &ev) { const TCgiParameters &cgi = ev->Get()->Request.GetPostParams(); - if (cgi.Has("chunksLockByRange")) { - ui32 begin = strtoul(cgi.Get("chunksLockBegin").c_str(), nullptr, 10); - ui32 end = strtoul(cgi.Get("chunksLockEnd").c_str(), nullptr, 10); - TEvChunksLock evLock(true, begin, end, 0); - auto* request = PDisk->ReqCreator.CreateFromEv<TChunksLock>(evLock, ev->Sender); - PDisk->InputRequest(request); - } else if (cgi.Has("chunksLockByCount")) { - ui32 begin = strtoul(cgi.Get("chunksLockBegin").c_str(), nullptr, 10); - ui32 count = strtoul(cgi.Get("chunksLockCount").c_str(), nullptr, 10); - TEvChunksLock evLock(false, begin, 0, count); - auto* request = PDisk->ReqCreator.CreateFromEv<TChunksLock>(evLock , ev->Sender); - PDisk->InputRequest(request); - } else if (cgi.Has("chunksUnlock")) { - auto* request = PDisk->ReqCreator.CreateFromEv<TChunksUnlock>(NPDisk::TEvChunksUnlock(), ev->Sender); - PDisk->InputRequest(request); - } else if (cgi.Has("restartPDisk")) { + + TAppData* app = NKikimr::AppData(TActivationContext::AsActorContext()); + bool enableChunkLocking = app->FeatureFlags.GetEnableChunkLocking(); + + if (enableChunkLocking) { + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + if (cgi.Has("chunkLockByCount")) { + TEvChunkLock::ELockFrom lockFrom = TEvChunkLock::LockFromByName(cgi.Get("lockFrom")); + ui32 count = strtoul(cgi.Get("count").c_str(), nullptr, 10); + if (lockFrom == TEvChunkLock::ELockFrom::PERSONAL_QUOTA) { + if (cgi.Has("byVDiskId")) { + bool isGenSet = true; + auto vdiskId = VDiskIDFromString(cgi.Get("vdiskId"), &isGenSet); + TEvChunkLock evLock(lockFrom, vdiskId, isGenSet, count, TColor::GREEN); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(evLock, ev->Sender); + PDisk->InputRequest(request); + } else { + ui8 owner = strtoul(cgi.Get("owner").c_str(), nullptr, 10); + TEvChunkLock evLock(lockFrom, owner, count, TColor::GREEN); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(evLock, ev->Sender); + PDisk->InputRequest(request); + } + } else { + TEvChunkLock evLock(lockFrom, count, TColor::GREEN); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(evLock, ev->Sender); + PDisk->InputRequest(request); + } + } else if (cgi.Has("chunkLockByColor")) { + TEvChunkLock::ELockFrom lockFrom = TEvChunkLock::LockFromByName(cgi.Get("lockFrom")); + TColor::E color = ColorByName(cgi.Get("spaceColor")); + if (lockFrom == TEvChunkLock::ELockFrom::PERSONAL_QUOTA) { + if (cgi.Has("byVDiskId")) { + bool isGenSet = true; + auto vdiskId = VDiskIDFromString(cgi.Get("vdiskId"), &isGenSet); + TEvChunkLock evLock(lockFrom, vdiskId, isGenSet, 0, color); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(evLock, ev->Sender); + PDisk->InputRequest(request); + } else { + ui8 owner = strtoul(cgi.Get("owner").c_str(), nullptr, 10); + TEvChunkLock evLock(lockFrom, owner, 0, color); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(evLock, ev->Sender); + PDisk->InputRequest(request); + } + } else { + TEvChunkLock evLock(lockFrom, 0, color); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkLock>(evLock, ev->Sender); + PDisk->InputRequest(request); + } + } else if (cgi.Has("chunkUnlock")) { + TEvChunkLock::ELockFrom lockFrom = TEvChunkLock::LockFromByName(cgi.Get("lockFrom")); + if (lockFrom == TEvChunkLock::ELockFrom::PERSONAL_QUOTA) { + if (cgi.Has("byVDiskId")) { + bool isGenSet = true; + auto vdiskId = VDiskIDFromString(cgi.Get("vdiskId"), &isGenSet); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkUnlock>( + NPDisk::TEvChunkUnlock(lockFrom, vdiskId, isGenSet), ev->Sender); + PDisk->InputRequest(request); + } else { + ui8 owner = strtoul(cgi.Get("owner").c_str(), nullptr, 10); + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkUnlock>( + NPDisk::TEvChunkUnlock(lockFrom, owner), ev->Sender); + PDisk->InputRequest(request); + } + } else { + auto* request = PDisk->ReqCreator.CreateFromEv<TChunkUnlock>( + NPDisk::TEvChunkUnlock(lockFrom), ev->Sender); + PDisk->InputRequest(request); + } + } + } + if (cgi.Has("restartPDisk")) { if (Cfg->SectorMap || CurrentStateFunc() == &TPDiskActor::StateError) { Send(NodeWardenServiceId, new TEvBlobStorage::TEvAskRestartPDisk(PDisk->PDiskId)); // Send responce later when restart command will be received @@ -1043,8 +1098,8 @@ public: hFunc(NPDisk::TEvSlay, Handle); hFunc(NPDisk::TEvChunkReserve, Handle); hFunc(NPDisk::TEvChunkForget, Handle); - hFunc(NPDisk::TEvChunksLock, Handle); - hFunc(NPDisk::TEvChunksUnlock, Handle); + hFunc(NPDisk::TEvChunkLock, Handle); + hFunc(NPDisk::TEvChunkUnlock, Handle); hFunc(NPDisk::TEvYardControl, Handle); hFunc(NPDisk::TEvAskForCutLog, Handle); hFunc(NPDisk::TEvConfigureScheduler, Handle); diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_chunk_tracker.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_chunk_tracker.h index 444830953c..dff4eb4925 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_chunk_tracker.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_chunk_tracker.h @@ -196,6 +196,10 @@ public: } str << "</table>"; } + + ui32 ColorFlagLimit(TOwner id, NKikimrBlobStorage::TPDiskSpaceColor::E color) { + return QuotaForOwner[id].ColorFlagLimit(color); + } }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -444,6 +448,14 @@ public: str << "<h4>OwnerQuota</h4>"; OwnerQuota->PrintHTML(str, SharedQuota.Get(), &ColorBorder); } + + ui32 ColorFlagLimit(TOwner owner, NKikimrBlobStorage::TPDiskSpaceColor::E color) { + if (IsOwnerUser(owner)) { + return OwnerQuota->ColorFlagLimit(owner, color); + } else { + return GlobalQuota->ColorFlagLimit(owner, color); + } + } }; } // NPDisk diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp index 91897656ba..d7e554675c 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp @@ -985,95 +985,239 @@ TPDisk::EChunkReadPieceResult TPDisk::ChunkReadPiece(TIntrusivePtr<TChunkRead> & //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Chunk locking //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void TPDisk::ChunksLockByRange(TFreeChunks &freeChunks, ui32 begin, ui32 end, TVector<ui32> &lockedChunks) { - ui32 freeChunksCount = freeChunks.Size(); - TVector<ui32> tmpChunks; - tmpChunks.reserve(freeChunksCount); - for (ui32 i = 0; i < freeChunksCount; ++i) { - ui32 idx = freeChunks.Pop(); - tmpChunks.push_back(idx); - } - for (ui32 i = 0; i < freeChunksCount; ++i) { - ui32 idx = tmpChunks.back(); - tmpChunks.pop_back(); - if (begin <= idx && idx < end) { - ChunkState[idx].OwnerId = OwnerLocked; - ChunkState[idx].CommitState = TChunkState::FREE; - lockedChunks.push_back(idx); - Mon.LockedChunks->Inc(); - } else { - freeChunks.Push(idx); - } +TVector<TChunkIdx> TPDisk::LockChunksForOwner(TOwner owner, const ui32 count, TString &errorReason) { + // chunkIdx = 0 is deprecated and will not be soon removed + TGuard<TMutex> guard(StateMutex); + + const ui32 sharedFree = Keeper.GetFreeChunkCount() - 1; + i64 ownerFree = Keeper.GetOwnerFree(owner); + auto color = Keeper.EstimateSpaceColor(owner, count); + + auto makeError = [&](TString info) { + guard.Release(); + TStringStream str; + str << "PDiskId# " << PDiskId + << " Can't lock " << count << " chunks" + << " for ownerId# " << owner + << " sharedFree# " << sharedFree + << " ownerFree# " << ownerFree + << " estimatedColor after lock# " << NKikimrBlobStorage::TPDiskSpaceColor::E_Name(color) + << " " << info + << " Marker# BPD21"; + errorReason = str.Str(); + LOG_ERROR_S(*ActorSystem, NKikimrServices::BS_PDISK, str.Str()); + }; + + if (ownerFree < count) { + makeError("Not enough free chunks"); + return {}; } + + if (sharedFree <= count || color == NKikimrBlobStorage::TPDiskSpaceColor::BLACK) { + makeError(""); + return {}; + } + + TVector<TChunkIdx> chunks = Keeper.PopOwnerFreeChunks(owner, count, errorReason); + if (chunks.empty()) { + makeError("PopOwnerFreeChunks failed"); + return {}; + } + + for (TChunkIdx chunkIdx : chunks) { + TChunkState &state = ChunkState[chunkIdx]; + Y_VERIFY_S(state.OwnerId == OwnerUnallocated + || state.OwnerId == OwnerUnallocatedTrimmed + || state.CommitState == TChunkState::FREE, + "PDiskId# " << PDiskId << " chunkIdx# " << chunkIdx << " desired ownerId# " << owner + << " state# " << state.ToString()); + LOG_INFO_S(*ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# " << PDiskId << " chunkIdx# " << chunkIdx << + " locked, ownerId# " << state.OwnerId << " -> " << owner); + state.OwnerId = owner; + state.CommitState = TChunkState::LOCKED; + Mon.LockedChunks->Inc(); + } + OwnerLocks[owner] += chunks.size(); + return chunks; } -void TPDisk::ChunksLockByNumber(ui32 begin, ui32 count, TVector<ui32> &lockedChunks) { - begin = begin > 0 ? begin : 1; - TVector<ui32> tmpChunks; - tmpChunks.reserve(Keeper.GetFreeChunkCount()); - TString errorReason; - while (ui32 idx = Keeper.PopFreeChunkHack(errorReason)) { - tmpChunks.push_back(idx); +std::unique_ptr<TEvChunkLockResult> TPDisk::ChunkLockFromQuota(TOwner owner, ui32 number) { + TStringStream errorReason; + TGuard<TMutex> guard(StateMutex); + + std::unique_ptr<NPDisk::TEvChunkLockResult> result; + TString allocateError; + TVector<TChunkIdx> chunks = LockChunksForOwner(owner, number, allocateError); + errorReason << allocateError; + + if (chunks.empty()) { + result.reset(new NPDisk::TEvChunkLockResult(NKikimrProto::OUT_OF_SPACE, + {}, Keeper.GetFreeChunkCount(), errorReason.Str())); + } else { + result.reset(new NPDisk::TEvChunkLockResult(NKikimrProto::OK, + std::move(chunks), Keeper.GetFreeChunkCount())); } - Sort(tmpChunks.begin(), tmpChunks.end()); - for (ui32 i = 0; i < tmpChunks.size(); ++i) { - ui32 idx = tmpChunks[i]; - if (begin <= idx && lockedChunks.size() < count) { - ChunkState[idx].OwnerId = OwnerLocked; - ChunkState[idx].CommitState = TChunkState::FREE; - lockedChunks.push_back(idx); - Mon.LockedChunks->Inc(); - } else { - Keeper.PushFreeChunkHack(idx); - } + + guard.Release(); + return std::move(result); +} + +std::unique_ptr<TEvChunkLockResult> TPDisk::ChunkLockFromQuota(TOwner owner, NKikimrBlobStorage::TPDiskSpaceColor::E color) { + ui32 number = Keeper.ColorFlagLimit(owner, color); + ui32 used = Keeper.GetOwnerUsed(owner); + if (number <= used) { + LOG_ERROR_S(*ActorSystem, NKikimrServices::BS_PDISK, + "Can't lock chunks by color# " << TPDiskSpaceColor_Name(color) << + ", this space color flag is already raised. Marker# BPD33"); + return std::unique_ptr<TEvChunkLockResult>(new NPDisk::TEvChunkLockResult(NKikimrProto::ERROR, + {}, Keeper.GetFreeChunkCount(), "Space color flag is already raised")); + } else { + return std::move(ChunkLockFromQuota(owner, number - used)); } } -void TPDisk::ChunksLock(TChunksLock &evChunksLock) { - TVector<ui32> lockedChunks; - if (evChunksLock.LockByRange) { - if (evChunksLock.Begin < evChunksLock.End) { - lockedChunks.reserve(evChunksLock.End - evChunksLock.Begin); +void TPDisk::ChunkLock(TChunkLock &evChunkLock) { + std::unique_ptr<TEvChunkLockResult> result; + + TGuard<TMutex> guard(StateMutex); + auto sendError = [&] (TChunkLock &evChunkLock, TString info, TString marker) { + TStringStream str; + str << "Can't lock " << evChunkLock.Count << " chunks"; + if (evChunkLock.Owner) { + str << " for owner# " << evChunkLock.Owner; + } else if (evChunkLock.ByVDiskId) { + if (evChunkLock.IsGenerationSet) { + str << " for vdisk# " << evChunkLock.VDiskId.ToString(); + } else { + str << " for vdisk# " << evChunkLock.VDiskId.ToStringWOGeneration(); + } + } + if (!info.empty()) { + str << ": " << info; } + str << " Marker# " << marker; + + LOG_ERROR_S(*ActorSystem, NKikimrServices::BS_PDISK, str.Str()); + guard.Release(); + ActorSystem->Send(evChunkLock.Sender, new NPDisk::TEvChunkLockResult( + NKikimrProto::ERROR, {}, Keeper.GetFreeChunkCount(), str.Str())); + }; + + if (evChunkLock.LockFrom == TEvChunkLock::ELockFrom::COUNT) { + sendError(evChunkLock, "incorrect LockFrom in query", "BPD35"); + return; + } + + TOwner owner; + if (evChunkLock.LockFrom == TEvChunkLock::ELockFrom::LOG) { + owner = OwnerSystem; } else { - lockedChunks.reserve(evChunksLock.Count); + if (evChunkLock.ByVDiskId) { + if (evChunkLock.VDiskId == TVDiskID::InvalidId) { + sendError(evChunkLock, "invalid VDiskId", "BPD37"); + } + auto it = VDiskOwners.begin(); + for (; it != VDiskOwners.end(); ++it) { + if (evChunkLock.IsGenerationSet && it->first == evChunkLock.VDiskId) { + break; + } else if (!evChunkLock.IsGenerationSet && it->first.SameExceptGeneration(evChunkLock.VDiskId)) { + break; + } + } + if (it == VDiskOwners.end()) { + sendError(evChunkLock, "didn't find owner by given VDisk Id", "BPD34"); + return; + } + owner = it->second; + } else { + owner = evChunkLock.Owner; + } } - TGuard<TMutex> guard(StateMutex); - if (evChunksLock.LockByRange) { - // TODO(cthulhu): Implement lock by range for owned chunks - //ChunksLockByRange(TrimmedFreeChunks, evChunksLock.Begin, evChunksLock.End, lockedChunks); - //ChunksLockByRange(UntrimmedFreeChunks, evChunksLock.Begin, evChunksLock.End, lockedChunks); - LOG_INFO(*ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# %" PRIu32 " Locked %" PRIu32 \ - " chunks in range [%" PRIu32 ", %" PRIu32 ")", (ui32)PDiskId, (ui32)lockedChunks.size(), - (ui32)evChunksLock.Begin, (ui32)evChunksLock.End); + + if (evChunkLock.Count) { + result.reset(ChunkLockFromQuota(owner, evChunkLock.Count).release()); } else { - ChunksLockByNumber(evChunksLock.Begin, evChunksLock.Count, lockedChunks); - LOG_INFO(*ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# %" PRIu32 " Locked %" PRIu32 \ - " chunks starting from %" PRIu32 "", (ui32)PDiskId, (ui32)lockedChunks.size(), (ui32)evChunksLock.Begin); + result.reset(ChunkLockFromQuota(owner, evChunkLock.Color).release()); } - ui32 availableChunkCount = Keeper.GetFreeChunkCount(); + + LOG_INFO(*ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# %" PRIu32 " Locked %" PRIu32 \ + " chunks from owner# " PRIu32, (ui32)PDiskId, (ui32)result->LockedChunks.size(), (ui32)owner); + guard.Release(); - ActorSystem->Send(evChunksLock.Sender, new NPDisk::TEvChunksLockResult(NKikimrProto::OK, lockedChunks, - availableChunkCount)); + ActorSystem->Send(evChunkLock.Sender, new NPDisk::TEvChunkLockResult(NKikimrProto::OK, result->LockedChunks, + Keeper.GetFreeChunkCount())); } -void TPDisk::ChunksUnlock(TChunksUnlock &evChunksUnlock) { +void TPDisk::ChunkUnlock(TChunkUnlock &evChunkUnlock) { TGuard<TMutex> guard(StateMutex); + TOwner owner; + + auto sendError = [&] (TChunkUnlock &evChunkUnlock, TString info, TString marker) { + TStringStream str; + str << "Can't unlock chunks"; + if (evChunkUnlock.Owner) { + str << " for owner# " << evChunkUnlock.Owner; + } else if (evChunkUnlock.ByVDiskId) { + if (evChunkUnlock.IsGenerationSet) { + str << " for vdisk# " << evChunkUnlock.VDiskId.ToString(); + } else { + str << " for vdisk# " << evChunkUnlock.VDiskId.ToStringWOGeneration(); + } + } + if (!info.empty()) { + str << ": " << info; + } + str << " Marker# " << marker; + + LOG_ERROR_S(*ActorSystem, NKikimrServices::BS_PDISK, str.Str()); + guard.Release(); + ActorSystem->Send(evChunkUnlock.Sender, new NPDisk::TEvChunkUnlockResult(NKikimrProto::ERROR, 0, str.Str())); + }; + + if (evChunkUnlock.LockFrom == TEvChunkLock::ELockFrom::LOG) { + owner = OwnerSystem; + } else { + if (evChunkUnlock.ByVDiskId) { + if (evChunkUnlock.VDiskId == TVDiskID::InvalidId) { + sendError(evChunkUnlock, "invalid VDiskId", "BPD38"); + return; + } + auto it = VDiskOwners.begin(); + for (; it != VDiskOwners.end(); ++it) { + if (evChunkUnlock.IsGenerationSet && it->first == evChunkUnlock.VDiskId) { + break; + } else if (!evChunkUnlock.IsGenerationSet && it->first.SameExceptGeneration(evChunkUnlock.VDiskId)) { + break; + } + } + if (it == VDiskOwners.end()) { + sendError(evChunkUnlock, "didn't find owner by given VDisk Id", "BPD36"); + return; + } + owner = it->second; + } else { + owner = evChunkUnlock.Owner; + } + } + + ui32 lockedChunks = OwnerLocks[owner]; ui32 unlockedChunks = 0; - for (ui32 chunkIdx = 0; chunkIdx < ChunkState.size(); ++chunkIdx) { - if (ChunkState[chunkIdx].OwnerId == OwnerLocked) { + for (ui32 chunkIdx = 0; chunkIdx < ChunkState.size() && unlockedChunks < lockedChunks; ++chunkIdx) { + if (ChunkState[chunkIdx].CommitState == TChunkState::LOCKED && ChunkState[chunkIdx].OwnerId == owner) { TChunkState &state = ChunkState[chunkIdx]; state.OwnerId = OwnerUnallocated; state.CommitState = TChunkState::FREE; Mon.LockedChunks->Dec(); - Keeper.PushFreeChunkHack(chunkIdx); + Keeper.PushFreeOwnerChunk(owner, chunkIdx); + ++unlockedChunks; } - ++unlockedChunks; } + + OwnerLocks[owner] = 0; guard.Release(); LOG_INFO(*ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# %" PRIu32 " Unlocked %" PRIu32 "", (ui32)PDiskId, (ui32)unlockedChunks); - ActorSystem->Send(evChunksUnlock.Sender, new NPDisk::TEvChunksUnlockResult(NKikimrProto::OK, unlockedChunks)); + ActorSystem->Send(evChunkUnlock.Sender, new NPDisk::TEvChunkUnlockResult(NKikimrProto::OK, unlockedChunks)); return; } @@ -1779,6 +1923,8 @@ void TPDisk::ForceDeleteChunk(TChunkIdx chunkIdx) { [[fallthrough]]; case TChunkState::DATA_RESERVED: [[fallthrough]]; + case TChunkState::LOCKED: + [[fallthrough]]; case TChunkState::DATA_COMMITTED: state.OwnerId = OwnerUnallocated; state.CommitState = TChunkState::FREE; @@ -1817,6 +1963,8 @@ void TPDisk::KillOwner(TOwner owner, TOwnerRound killOwnerRound, TCompletionEven LOG_DEBUG(*ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# %" PRIu32 " Line# %" PRIu32 " --CommitedDataChunks# %" PRIi64 " chunkIdx# %" PRIu32 " Marker# BPD84", (ui32)PDiskId, (ui32)__LINE__, (i64)Mon.CommitedDataChunks->Val(), (ui32)i); + } else if (state.CommitState == TChunkState::LOCKED) { + Mon.LockedChunks->Dec(); } if (state.CommitState == TChunkState::DATA_ON_QUARANTINE) { if (!pushedOwnerIntoQuarantine) { @@ -2195,11 +2343,11 @@ void TPDisk::ProcessFastOperationsQueue() { case ERequestType::RequestChunkReserve: ChunkReserve(static_cast<TChunkReserve&>(*req)); break; - case ERequestType::RequestChunksLock: - ChunksLock(static_cast<TChunksLock&>(*req)); + case ERequestType::RequestChunkLock: + ChunkLock(static_cast<TChunkLock&>(*req)); break; - case ERequestType::RequestChunksUnlock: - ChunksUnlock(static_cast<TChunksUnlock&>(*req)); + case ERequestType::RequestChunkUnlock: + ChunkUnlock(static_cast<TChunkUnlock&>(*req)); break; case ERequestType::RequestAskForCutLog: SendCutLog(static_cast<TAskForCutLog&>(*req)); @@ -2777,9 +2925,9 @@ bool TPDisk::PreprocessRequest(TRequestBase *request) { ev.SetOwnerGroupType(OwnerData[ev.Owner].IsStaticGroupOwner()); break; } - case ERequestType::RequestChunksLock: + case ERequestType::RequestChunkLock: break; - case ERequestType::RequestChunksUnlock: + case ERequestType::RequestChunkUnlock: break; case ERequestType::RequestYardControl: { diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h index e0704efdd9..beeec00d4d 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h @@ -173,6 +173,10 @@ public: TAtomic SlowDeviceMs = 0; const bool UseHugePages; + + // Chunk locking + TMap<TOwner, ui32> OwnerLocks; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Initialization TPDisk(const TIntrusivePtr<TPDiskConfig> cfg, const TIntrusivePtr<::NMonitoring::TDynamicCounters>& counters); @@ -266,10 +270,13 @@ public: ui64 *reallyReadBytes); void SplitChunkJobSize(ui32 totalSize, ui32 *outSmallJobSize, ui32 *outLargeJObSize, ui32 *outSmallJobCount); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void ChunksLockByRange(TFreeChunks &freeChunks, ui32 begin, ui32 end, TVector<ui32> &lockedChunks); - void ChunksLockByNumber(ui32 begin, ui32 number, TVector<ui32> &lockedChunks); - void ChunksLock(TChunksLock &evChunksLock); - void ChunksUnlock(TChunksUnlock &evChunksUnlock); + // Chunk locking + TVector<TChunkIdx> LockChunksForOwner(TOwner owner, const ui32 count, TString &errorReason); + std::unique_ptr<TEvChunkLockResult> ChunkLockFromQuota(TOwner owner, ui32 number); + std::unique_ptr<TEvChunkLockResult> ChunkLockFromQuota(TOwner owner, NKikimrBlobStorage::TPDiskSpaceColor::E color); + void ChunkLock(TChunkLock &evChunkLock); + void ChunkUnlock(TChunkUnlock &evChunkUnlock); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Chunk reservation TVector<TChunkIdx> AllocateChunkForOwner(const TRequestBase *req, const ui32 count, TString &errorReason); void ChunkReserve(TChunkReserve &evChunkReserve); @@ -281,7 +288,7 @@ public: void RenderState(IOutputStream &str, THttpInfo &httpInfo); void OutputHtmlOwners(TStringStream &str); void OutputHtmlLogChunksDetails(TStringStream &str); - void OutputHtmlChunksLockUnlockInfo(TStringStream &str); + void OutputHtmlChunkLockUnlockInfo(TStringStream &str); void HttpInfo(THttpInfo &httpInfo); // Called by actor void EventUndelivered(TUndelivered &req); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp index 5565a0c829..5930e2bffc 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp @@ -304,41 +304,91 @@ void TPDisk::OutputHtmlLogChunksDetails(TStringStream &str) { } } -void TPDisk::OutputHtmlChunksLockUnlockInfo(TStringStream &str) { +void TPDisk::OutputHtmlChunkLockUnlockInfo(TStringStream &str) { + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + bool chunkLockingEnabled = NKikimr::AppData(ActorSystem)->FeatureFlags.GetEnableChunkLocking(); + + auto commonParams = [&] (TStringStream &str, TString requestName) { + for (TEvChunkLock::ELockFrom from : { TEvChunkLock::ELockFrom::LOG, TEvChunkLock::ELockFrom::PERSONAL_QUOTA } ) { + str << "<input id='" << requestName << "LockFrom_" << TEvChunkLock::ELockFrom_Name(from) << + "' name='lockFrom' type='radio' value='" << TEvChunkLock::ELockFrom_Name(from) << "'"; + if (from == TEvChunkLock::ELockFrom::PERSONAL_QUOTA) { + str << " checked"; + } + str << "/>"; + str << "<label for='" << requestName << "LockFrom_'" << TEvChunkLock::ELockFrom_Name(from) << "'>" << + TEvChunkLock::ELockFrom_Name(from) << "</label>"; + } + str << "<br>"; + str << "<input id='" << requestName << "ByVDiskId' name='byVDiskId' type='checkbox'/>"; + str << "<label for='" << requestName << "ByVDiskId'>" << "By VDisk Id" << "</label>"; + str << "<br>"; + str << "<input id='" << requestName << "Owner' name='owner' type='text' value='" << 4 << "'/>"; + str << "<label for='" << requestName << "Owner'>" << "Owner Id" << "</label>"; + str << "<br>"; + str << "<input id='" << requestName << "VDiskId' name='vdiskId' type='text' value='" << "[0:_:0:0:0]" << "'/>"; + str << "<label for='" << requestName << "VDiskId'>" << "VDisk Id" << "</label>"; + }; + + HTML(str) { - str << "<button type='button' class='btn btn-default' data-toggle='collapse' style='margin:5px' \ - data-target='#lockByRangeCollapse'> Lock by range </button>"; - str << "<button type='button' class='btn btn-default' data-toggle='collapse' style='margin:5px' \ - data-target='#lockByCountCollapse'> Lock by count </button>"; + if (chunkLockingEnabled) { + str << "<button type='button' class='btn btn-default' data-toggle='collapse' style='margin:5px' \ + data-target='#lockByColorCollapse'> Lock by color </button>"; + str << "<button type='button' class='btn btn-default' data-toggle='collapse' style='margin:5px' \ + data-target='#lockByCountCollapse'> Lock by count </button>"; + str << "<button type='button' class='btn btn-default' data-toggle='collapse' style='margin:5px' \ + data-target='#unlockCollapse'> Unlock </button>"; - str << "<div id='lockByRangeCollapse' class='collapse'>"; - str << "<form class='form_horizontal' method='post'>"; - LABEL_CLASS_FOR("control-label", "begin") { str << "Begin "; } - str << "<input id='inputBegin' name='chunksLockBegin' type='text' value='" << 1 << "'/>"; - LABEL_CLASS_FOR("control-label", "end") { str << " End "; } - str << "<input id='inputEnd' name='chunksLockEnd' type='text' value='" << - ChunkState.size() << "'/>"; - str << "<button type='submit' name='chunksLockByRange' class='btn btn-default'\ - style='background:red; margin:5px'>Lock by range</button>"; - str << "</form>"; - str << "</div>"; + str << "<div id='lockByColorCollapse' class='collapse'>"; + str << "<form class='form_horizontal' method='post'>"; + LABEL_CLASS_FOR("control-label", "color") { str << "Color"; } + for (TColor::E color : { TColor::CYAN, TColor::LIGHT_YELLOW, TColor::YELLOW, TColor::LIGHT_ORANGE, + TColor::ORANGE, TColor::RED, TColor::BLACK} ) { + str << "<input id='inputColor_" << TPDiskSpaceColor_Name(color) << "' name='spaceColor' type='radio' value='" + << TPDiskSpaceColor_Name(color) << "'"; + if (color == TColor::CYAN) { + str << " checked"; + } + str << "/>"; + TString textColor = color == TColor::BLACK ? "white" : "black"; + str << "<label for='inputColor_'" << TPDiskSpaceColor_Name(color) << "' style='background:" << + TPDiskSpaceColor_HtmlCode(color) << "; color:" << textColor << ";'>" << + TPDiskSpaceColor_Name(color) << "</label>"; + } + + str << "<br>"; + commonParams(str, "lockByColor"); + str << "<br>"; + + str << "<button type='submit' name='chunkLockByColor' class='btn btn-default'\ + style='background:red; margin:5px'>Lock by color</button>"; + str << "</form>"; + str << "</div>"; - str << "<div id='lockByCountCollapse' class='collapse'>"; - str << "<form class='form_horizontal' method='post'>"; - LABEL_CLASS_FOR("control-label", "begin") { str << "Begin "; } - str << "<input id='inputBegin' name='chunksLockBegin' type='text' value='" << 1 << "'/>"; - LABEL_CLASS_FOR("control-label", "count") { str << " Count "; } - str << "<input id='inputCount' name='chunksLockCount' type='text' value='" << - ChunkState.size() << "'/>"; - str << "<button type='submit' name='chunksLockByCount' class='btn btn-default' \ - style='background:red; margin:5px'>Lock by count</button>"; - str << "</form>"; - str << "</div>"; + str << "<div id='lockByCountCollapse' class='collapse'>"; + str << "<form class='form_horizontal' method='post'>"; + LABEL_CLASS_FOR("control-label", "count") { str << "Count"; } + str << "<input id='inputByCountCount' name='count' type='text' value='" << + ChunkState.size() << "'/>"; + str << "<br>"; + commonParams(str, "lockByCount"); + str << "<br>"; + str << "<button type='submit' name='chunkLockByCount' class='btn btn-default' \ + style='background:red; margin:5px'>Lock by count</button>"; + str << "</form>"; + str << "</div>"; + + str << "<div id='unlockCollapse' class='collapse'>"; + str << "<form class='form_horizontal' method='post'>"; + commonParams(str, "unlock"); + str << "<br>"; + str << "<button type='submit' name='chunkUnlock' class='btn btn-default' \ + style='background:green; margin:5px'>Unlock</button>"; + str << "</form>"; + str << "</div>"; + } - str << "<form method='post'>"; - str << "<button type='submit' name='chunksUnlock' class='btn btn-default' \ - style='background:green; margin:5px'>Unlock All</button>"; - str << "</form>"; COLLAPSED_BUTTON_CONTENT("chunksStateTable", "Chunks State") { TABLE_CLASS ("") { const size_t columns = 50; @@ -360,6 +410,9 @@ void TPDisk::OutputHtmlChunksLockUnlockInfo(TStringStream &str) { if (idx < size) { const TChunkState &chunk = ChunkState[idx]; TABLED() { + str << "<span style='color:"; + str << (chunk.CommitState == TChunkState::LOCKED ? "red" : "black"); + str << ";'>"; if (chunk.OwnerId == (TOwner) OwnerSystem) { str << "L"; } else if (chunk.OwnerId == OwnerUnallocated) { @@ -370,10 +423,11 @@ void TPDisk::OutputHtmlChunksLockUnlockInfo(TStringStream &str) { str << "X"; } else { str << (ui32)chunk.OwnerId; - if (chunk.CommitState != TChunkState::DATA_COMMITTED) { + if (chunk.CommitState != TChunkState::DATA_COMMITTED && chunk.CommitState != TChunkState::LOCKED) { str << "-"; } } + str << "</span>"; } } else { TABLED() {} @@ -446,7 +500,7 @@ void TPDisk::HttpInfo(THttpInfo &httpInfo) { str << "Chunks"; } DIV_CLASS("panel-body") { - OutputHtmlChunksLockUnlockInfo(str); + OutputHtmlChunkLockUnlockInfo(str); } } // Chunks diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_keeper.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_keeper.h index 8c298a672d..a3fa2cc0bc 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_keeper.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_keeper.h @@ -154,6 +154,10 @@ public: UntrimmedFreeChunks.Push(chunkIdx); } + ui32 ColorFlagLimit(TOwner owner, NKikimrBlobStorage::TPDiskSpaceColor::E color) { + return ChunkTracker.ColorFlagLimit(owner, color); + } + // // GUI // diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_quota_record.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_quota_record.h index ef728e3213..5e48d4df5e 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_quota_record.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_quota_record.h @@ -154,6 +154,29 @@ public: return TColor::BLACK; } } + + ui32 ColorFlagLimit(NKikimrBlobStorage::TPDiskSpaceColor::E color) { + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + + switch (color) { + case TColor::CYAN: + return AtomicGet(HardLimit) - AtomicGet(Cyan); + case TColor::LIGHT_YELLOW: + return AtomicGet(HardLimit) - AtomicGet(LightYellow); + case TColor::YELLOW: + return AtomicGet(HardLimit) - AtomicGet(Yellow); + case TColor::LIGHT_ORANGE: + return AtomicGet(HardLimit) - AtomicGet(LightOrange); + case TColor::ORANGE: + return AtomicGet(HardLimit) - AtomicGet(Orange); + case TColor::RED: + return AtomicGet(HardLimit) - AtomicGet(Red); + case TColor::BLACK: + return AtomicGet(HardLimit) - AtomicGet(Black); + default: + return 0; + } + } }; } // NPDisk diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_request_id.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_request_id.h index 21d680884f..ff5c1937cf 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_request_id.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_request_id.h @@ -67,8 +67,8 @@ struct TReqId { ChunkTrim = 48, Harakiri = 49, Slay = 50, - ChunksLock = 51, - ChunksUnlock = 52, + ChunkLock = 51, + ChunkUnlock = 52, ChunkReserve = 53, ConfigureScheduler = 54, Undelivered = 55, @@ -126,8 +126,8 @@ enum class ERequestType { RequestHarakiri, RequestYardSlay, RequestChunkReserve, - RequestChunksLock, - RequestChunksUnlock, + RequestChunkLock, + RequestChunkUnlock, RequestYardControl, RequestAskForCutLog, RequestConfigureScheduler, diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h index 9d7797adbf..83dcdb1518 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_requestimpl.h @@ -613,39 +613,55 @@ public: // // TChunkLock // -class TChunksLock : public TRequestBase { +class TChunkLock : public TRequestBase { public: - bool LockByRange; - ui32 Begin; - ui32 End; + NPDisk::TEvChunkLock::ELockFrom LockFrom; + bool ByVDiskId; + TOwner Owner; + TVDiskID VDiskId; + bool IsGenerationSet; ui32 Count; + NKikimrBlobStorage::TPDiskSpaceColor::E Color; - TChunksLock(const NPDisk::TEvChunksLock &ev, const TActorId &sender, TAtomicBase reqIdx) - : TRequestBase(sender, TReqId(TReqId::ChunksLock, reqIdx), 0, 0, NPriInternal::Other) - , LockByRange(ev.LockByRange) - , Begin(ev.Begin) - , End(ev.End) + TChunkLock(const NPDisk::TEvChunkLock &ev, const TActorId &sender, TAtomicBase reqIdx) + : TRequestBase(sender, TReqId(TReqId::ChunkLock, reqIdx), 0, 0, NPriInternal::Other) + , LockFrom(ev.LockFrom) + , ByVDiskId(ev.ByVDiskId) + , Owner(ev.Owner) + , VDiskId(ev.VDiskId) + , IsGenerationSet(ev.IsGenerationSet) , Count(ev.Count) + , Color(ev.Color) {} ERequestType GetType() const override { - return ERequestType::RequestChunksLock; + return ERequestType::RequestChunkLock; } }; // -// TChunksUnlock +// TChunkUnlock // -class TChunksUnlock : public TRequestBase { +class TChunkUnlock : public TRequestBase { public: - TChunksUnlock(const NPDisk::TEvChunksUnlock &ev, const TActorId &sender, TAtomicBase reqIdx) - : TRequestBase(sender, TReqId(TReqId::ChunksUnlock, reqIdx), 0, 0, NPriInternal::Other) + NPDisk::TEvChunkLock::ELockFrom LockFrom; + bool ByVDiskId; + TOwner Owner; + TVDiskID VDiskId; + bool IsGenerationSet; + + TChunkUnlock(const NPDisk::TEvChunkUnlock &ev, const TActorId &sender, TAtomicBase reqIdx) + : TRequestBase(sender, TReqId(TReqId::ChunkUnlock, reqIdx), 0, 0, NPriInternal::Other) + , LockFrom(ev.LockFrom) + , ByVDiskId(ev.ByVDiskId) + , Owner(ev.Owner) + , VDiskId(ev.VDiskId) + , IsGenerationSet(ev.IsGenerationSet) { - Y_UNUSED(ev); } ERequestType GetType() const override { - return ERequestType::RequestChunksUnlock; + return ERequestType::RequestChunkUnlock; } }; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h index d2982f5fc5..032a69f767 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_state.h @@ -156,6 +156,7 @@ struct TChunkState { DATA_DECOMMITTED, DATA_RESERVED_DECOMMIT_IN_PROGRESS, DATA_COMMITTED_DECOMMIT_IN_PROGRESS, + LOCKED, }; ui64 Nonce; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.cpp index 3340d314fd..d9e5b68425 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.cpp @@ -948,7 +948,9 @@ void TTestChunkReserve::TestFSM(const TActorContext &ctx) { TestStep += 10; }; -void TTestCheckSpace::TestFSM(const TActorContext &ctx) { +void TTestChunkLock::TestFSM(const TActorContext &ctx) { + using EFrom = NPDisk::TEvChunkLock::ELockFrom; + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; TString data("testdata"); VERBOSE_COUT("Test step " << TestStep); switch (TestStep) { @@ -961,35 +963,29 @@ void TTestCheckSpace::TestFSM(const TActorContext &ctx) { TEST_RESPONSE(EvYardInitResult, OK); Owner = LastResponse.Owner; OwnerRound = LastResponse.OwnerRound; - VERBOSE_COUT(" Sending TEvCheckSpace"); - ctx.Send(Yard, new NPDisk::TEvCheckSpace(Owner, OwnerRound)); + VERBOSE_COUT(" Sending TEvChunkLock from LOG"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::LOG, 0, TColor::YELLOW)); break; case 20: - TEST_RESPONSE(EvCheckSpaceResult, OK); - VERBOSE_COUT("Free# " << LastResponse.FreeChunks - << " Total# " << LastResponse.TotalChunks - << " Owned# " << LastResponse.UsedChunks); - UNIT_ASSERT(LastResponse.UsedChunks == 0); - UNIT_ASSERT(LastResponse.FreeChunks == 585); - UNIT_ASSERT(LastResponse.TotalChunks == 585); - VERBOSE_COUT(" Sending TEvChunkReserve"); - ctx.Send(Yard, new NPDisk::TEvChunkReserve(Owner, OwnerRound, 3)); + TEST_RESPONSE(EvChunkLockResult, OK); + ASSERT_YTHROW(!LastResponse.ChunkIds.empty(), "Didn't lock anything"); + VERBOSE_COUT(" Sending TEvChunkLock from PERSONAL_QUOTA by count"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::PERSONAL_QUOTA, Owner, 5, TColor::GREEN)); break; case 30: - TEST_RESPONSE(EvChunkReserveResult, OK); - ASSERT_YTHROW(LastResponse.ChunkIds.size() == 3, - "Unexpected ChunkIds.size() == " << LastResponse.ChunkIds.size()); - VERBOSE_COUT(" Sending TEvCheckSpace"); - ctx.Send(Yard, new NPDisk::TEvCheckSpace(Owner, OwnerRound)); + TEST_RESPONSE(EvChunkLockResult, OK); + ASSERT_YTHROW(LastResponse.ChunkIds.size() == 5, + "Unexpected LockedChunks.size() == " << LastResponse.ChunkIds.size()); + VERBOSE_COUT(" Sending TEvChunkLock from PERSONAL_QUOTA"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::PERSONAL_QUOTA, Owner, 0, TColor::RED)); break; case 40: - TEST_RESPONSE(EvCheckSpaceResult, OK); - VERBOSE_COUT("Free# " << LastResponse.FreeChunks - << " Total# " << LastResponse.TotalChunks - << " Owned# " << LastResponse.UsedChunks); - UNIT_ASSERT(LastResponse.UsedChunks == 3); - UNIT_ASSERT(LastResponse.FreeChunks == 582); - UNIT_ASSERT(LastResponse.TotalChunks == 585); + TEST_RESPONSE(EvChunkLockResult, OK); + ASSERT_YTHROW(!LastResponse.ChunkIds.empty(), "Didn't lock anything"); + ctx.Send(Yard, new NPDisk::TEvChunkReserve(Owner, OwnerRound, 10)); + break; + case 50: + TEST_RESPONSE(EvChunkReserveResult, OUT_OF_SPACE); VERBOSE_COUT("Done"); SignalDoneEvent(); break; @@ -1000,7 +996,10 @@ void TTestCheckSpace::TestFSM(const TActorContext &ctx) { TestStep += 10; }; -void TTestChunksLockByRange::TestFSM(const TActorContext &ctx) { +void TTestChunkUnlock::TestFSM(const TActorContext &ctx) { + using EFrom = NPDisk::TEvChunkLock::ELockFrom; + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + TString data("testdata"); VERBOSE_COUT("Test step " << TestStep); switch (TestStep) { case 0: @@ -1010,33 +1009,41 @@ void TTestChunksLockByRange::TestFSM(const TActorContext &ctx) { break; case 10: TEST_RESPONSE(EvYardInitResult, OK); - VERBOSE_COUT("Sending empty TEvChunksLock"); - ctx.Send(Yard, new NPDisk::TEvChunksLock(true, 1, 1, 0)); + Owner = LastResponse.Owner; + OwnerRound = LastResponse.OwnerRound; + VERBOSE_COUT(" Sending TEvChunkLock from LOG"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::LOG, 0, TColor::YELLOW)); break; case 20: - TEST_RESPONSE(EvChunksLockResult, OK); - ASSERT_YTHROW(LastResponse.ChunkIds.size() == 0, - "Unexpected ChunkIds.size() == " << LastResponse.ChunkIds.size()); - ChunksToBeLockedBegin = LastResponse.FreeChunks / 4; - ChunksToBeLockedEnd = LastResponse.FreeChunks * 3 / 4; - VERBOSE_COUT("Sending TEvChunksLock to lock range"); - ctx.Send(Yard, new NPDisk::TEvChunksLock(true, ChunksToBeLockedBegin, ChunksToBeLockedEnd, 0)); + TEST_RESPONSE(EvChunkLockResult, OK); + LockedNumLog = LastResponse.ChunkIds.size(); + ASSERT_YTHROW(LockedNumLog, "Didn't lock anything"); + VERBOSE_COUT(" Sending TEvChunkLock from PERSONAL_QUOTA"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::PERSONAL_QUOTA, Owner, 0, TColor::RED)); break; case 30: - { - TEST_RESPONSE(EvChunksLockResult, OK); - VERBOSE_COUT("Recieve TEvChunksLockResult, starting to test it "); - ASSERT_YTHROW(LastResponse.ChunkIds.size() <= ChunksToBeLockedEnd - ChunksToBeLockedBegin, - "Unexpected ChunkIds.size() == " << LastResponse.ChunkIds.size()); - ui32 lockedChunksCount = LastResponse.ChunkIds.size(); - for (ui32 i = 0; i < lockedChunksCount; ++i) { - ASSERT_YTHROW(ChunksToBeLockedBegin <= LastResponse.ChunkIds[i] < ChunksToBeLockedEnd, - "Unexpected chunk locked == " << LastResponse.ChunkIds[i]); - } + TEST_RESPONSE(EvChunkLockResult, OK); + LockedNumPersonal = LastResponse.ChunkIds.size(); + ASSERT_YTHROW(LockedNumPersonal, "Didn't lock anything"); + ctx.Send(Yard, new NPDisk::TEvChunkUnlock(EFrom::LOG)); + break; + case 40: + TEST_RESPONSE(EvChunkUnlockResult, OK); + ASSERT_YTHROW(LastResponse.UnlockedChunks == LockedNumLog, "Expected" << LockedNumLog << + " unlocked chunks, got " << LastResponse.UnlockedChunks); + ctx.Send(Yard, new NPDisk::TEvChunkUnlock(EFrom::PERSONAL_QUOTA, Owner)); + break; + case 50: + TEST_RESPONSE(EvChunkUnlockResult, OK); + ASSERT_YTHROW(LastResponse.UnlockedChunks == LockedNumPersonal, "Expected" << LockedNumPersonal << + " unlocked chunks, got " << LastResponse.UnlockedChunks); + ctx.Send(Yard, new NPDisk::TEvChunkReserve(Owner, OwnerRound, 10)); + break; + case 60: + TEST_RESPONSE(EvChunkReserveResult, OK); VERBOSE_COUT("Done"); SignalDoneEvent(); break; - } default: ythrow TWithBackTrace<yexception>() << "Unexpected TestStep " << TestStep << Endl; break; @@ -1044,7 +1051,10 @@ void TTestChunksLockByRange::TestFSM(const TActorContext &ctx) { TestStep += 10; }; -void TTestChunksLockUnlockReserve::TestFSM(const TActorContext &ctx) { +void TTestChunkUnlockHarakiri::TestFSM(const TActorContext &ctx) { + using EFrom = NPDisk::TEvChunkLock::ELockFrom; + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + TString data("testdata"); VERBOSE_COUT("Test step " << TestStep); switch (TestStep) { case 0: @@ -1056,36 +1066,136 @@ void TTestChunksLockUnlockReserve::TestFSM(const TActorContext &ctx) { TEST_RESPONSE(EvYardInitResult, OK); Owner = LastResponse.Owner; OwnerRound = LastResponse.OwnerRound; - VERBOSE_COUT(" Sending TEvChunksLock"); - ctx.Send(Yard, new NPDisk::TEvChunksLock(false, 1, 0, 0)); + VERBOSE_COUT(" Sending TEvChunkLock from PERSONAL_QUOTA"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::PERSONAL_QUOTA, Owner, 0, TColor::RED)); break; case 20: - TEST_RESPONSE(EvChunksLockResult, OK); - ASSERT_YTHROW(LastResponse.ChunkIds.size() == 0, - "Unexpected ChunkIds.size() == " << LastResponse.ChunkIds.size()); - ChunksToBeLockedCount = LastResponse.FreeChunks / 2; - ctx.Send(Yard, new NPDisk::TEvChunksLock(false, 1, 0, ChunksToBeLockedCount)); + TEST_RESPONSE(EvChunkLockResult, OK); + VERBOSE_COUT(" Checking space to get TotalFree"); + ASSERT_YTHROW(LastResponse.ChunkIds.size(), "Didn't lock anything"); + ctx.Send(Yard, new NPDisk::TEvCheckSpace(Owner, OwnerRound)); break; case 30: - TEST_RESPONSE(EvChunksLockResult, OK); - ASSERT_YTHROW(LastResponse.ChunkIds.size() == ChunksToBeLockedCount, - "Unexpected ChunkIds.size() == " << LastResponse.ChunkIds.size()); - ctx.Send(Yard, new NPDisk::TEvChunksLock(false, 1, 0, (MIN_CHUNK_SIZE)+1)); + TEST_RESPONSE(EvCheckSpaceResult, OK); + TotalFree = LastResponse.TotalChunks; + VERBOSE_COUT(" Sending TEvHarakiri"); + ctx.Send(Yard, new NPDisk::TEvHarakiri(Owner, OwnerRound)); break; case 40: - TEST_RESPONSE(EvChunksLockResult, OK); - ctx.Send(Yard, new NPDisk::TEvChunkReserve(Owner, OwnerRound, 1)); + TEST_RESPONSE(EvHarakiriResult, OK); + VERBOSE_COUT(" Sending second TEvInit"); + ctx.Send(Yard, new NPDisk::TEvYardInit(3, VDiskID, *PDiskGuid)); break; case 50: - TEST_RESPONSE(EvChunkReserveResult, OUT_OF_SPACE); - ctx.Send(Yard, new NPDisk::TEvChunksUnlock()); + TEST_RESPONSE(EvYardInitResult, OK); + Owner = LastResponse.Owner; + OwnerRound = LastResponse.OwnerRound; + VERBOSE_COUT(" Checking space"); + ctx.Send(Yard, new NPDisk::TEvCheckSpace(Owner, OwnerRound)); break; case 60: - TEST_RESPONSE(EvChunksUnlockResult, OK); + TEST_RESPONSE(EvCheckSpaceResult, OK); + ASSERT_YTHROW(TotalFree = LastResponse.TotalChunks, "Didn't unlock chunks after Harakiri, expected " << + TotalFree << ", got " << LastResponse.TotalChunks); + VERBOSE_COUT("Done"); + SignalDoneEvent(); + break; + default: + ythrow TWithBackTrace<yexception>() << "Unexpected TestStep " << TestStep << Endl; + break; + } + TestStep += 10; +}; + +void TTestChunkUnlockRestart::TestFSM(const TActorContext &ctx) { + using EFrom = NPDisk::TEvChunkLock::ELockFrom; + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + TString data("testdata"); + VERBOSE_COUT("Test step " << TestStep); + switch (TestStep) { + case 0: + WhiteboardID = NNodeWhiteboard::MakeNodeWhiteboardServiceId(SelfId().NodeId()); + ctx.ExecutorThread.ActorSystem->RegisterLocalService(WhiteboardID, SelfId()); + NodeWardenId = MakeBlobStorageNodeWardenID(SelfId().NodeId()); + ctx.ExecutorThread.ActorSystem->RegisterLocalService(NodeWardenId, SelfId()); + ASSERT_YTHROW(LastResponse.Status == NKikimrProto::OK, StatusToString(LastResponse.Status)); + VERBOSE_COUT(" Sending TEvInit"); + ctx.Send(Yard, new NPDisk::TEvYardInit(2, VDiskID, *PDiskGuid, TActorId(), SelfId())); + break; + case 10: + TEST_RESPONSE(EvYardInitResult, OK); + VERBOSE_COUT(" Sending TEvChunkLock from PERSONAL_QUOTA"); + ctx.Send(Yard, new NPDisk::TEvChunkLock(EFrom::PERSONAL_QUOTA, Owner, 0, TColor::RED)); + break; + case 20: + TEST_RESPONSE(EvChunkLockResult, OK); + ASSERT_YTHROW(LastResponse.ChunkIds.size(), "Didn't lock anything"); + if (!LastResponse.whiteboardPDiskResult || !LastResponse.whiteboardPDiskResult->Record.HasPDiskId()) { + VERBOSE_COUT(" Whiteboard didn't return PDiskId, test terminated"); + VERBOSE_COUT("Terminated"); + SignalDoneEvent(); + break; + } + ctx.Send(NodeWardenId, new TEvBlobStorage::TEvAskRestartPDisk(LastResponse.whiteboardPDiskResult->Record.GetPDiskId())); + break; + case 30: + TEST_RESPONSE(EvHarakiri, OK); ctx.Send(Yard, new NPDisk::TEvChunkReserve(Owner, OwnerRound, 1)); break; - case 70: + case 40: + TEST_RESPONSE(EvChunkReserveResult, OK); + VERBOSE_COUT("Done"); + SignalDoneEvent(); + break; + default: + ythrow TWithBackTrace<yexception>() << "Unexpected TestStep " << TestStep << Endl; + break; + } + TestStep += 10; +}; + +void TTestCheckSpace::TestFSM(const TActorContext &ctx) { + TString data("testdata"); + VERBOSE_COUT("Test step " << TestStep); + switch (TestStep) { + case 0: + ASSERT_YTHROW(LastResponse.Status == NKikimrProto::OK, StatusToString(LastResponse.Status)); + VERBOSE_COUT(" Sending TEvInit"); + ctx.Send(Yard, new NPDisk::TEvYardInit(2, VDiskID, *PDiskGuid)); + break; + case 10: + TEST_RESPONSE(EvYardInitResult, OK); + Owner = LastResponse.Owner; + OwnerRound = LastResponse.OwnerRound; + VERBOSE_COUT(" Sending TEvCheckSpace"); + ctx.Send(Yard, new NPDisk::TEvCheckSpace(Owner, OwnerRound)); + break; + case 20: + TEST_RESPONSE(EvCheckSpaceResult, OK); + VERBOSE_COUT("Free# " << LastResponse.FreeChunks + << " Total# " << LastResponse.TotalChunks + << " Owned# " << LastResponse.UsedChunks); + UNIT_ASSERT(LastResponse.UsedChunks == 0); + UNIT_ASSERT(LastResponse.FreeChunks == 585); + UNIT_ASSERT(LastResponse.TotalChunks == 585); + VERBOSE_COUT(" Sending TEvChunkReserve"); + ctx.Send(Yard, new NPDisk::TEvChunkReserve(Owner, OwnerRound, 3)); + break; + case 30: TEST_RESPONSE(EvChunkReserveResult, OK); + ASSERT_YTHROW(LastResponse.ChunkIds.size() == 3, + "Unexpected ChunkIds.size() == " << LastResponse.ChunkIds.size()); + VERBOSE_COUT(" Sending TEvCheckSpace"); + ctx.Send(Yard, new NPDisk::TEvCheckSpace(Owner, OwnerRound)); + break; + case 40: + TEST_RESPONSE(EvCheckSpaceResult, OK); + VERBOSE_COUT("Free# " << LastResponse.FreeChunks + << " Total# " << LastResponse.TotalChunks + << " Owned# " << LastResponse.UsedChunks); + UNIT_ASSERT(LastResponse.UsedChunks == 3); + UNIT_ASSERT(LastResponse.FreeChunks == 582); + UNIT_ASSERT(LastResponse.TotalChunks == 585); VERBOSE_COUT("Done"); SignalDoneEvent(); break; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.h index 1c230ebc7f..764278e281 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_actions.h @@ -1229,51 +1229,77 @@ public: {} }; +class TTestChunkLock : public TBaseTest { + NPDisk::TOwner Owner; + NPDisk::TOwnerRound OwnerRound; -class TTestChunkReserve : public TBaseTest { + void TestFSM(const TActorContext &ctx); +public: + TTestChunkLock(const TIntrusivePtr<TTestConfig> &cfg) + : TBaseTest(cfg) + {} +}; + +class TTestChunkUnlock : public TBaseTest { NPDisk::TOwner Owner; NPDisk::TOwnerRound OwnerRound; + ui32 LockedNumLog; + ui32 LockedNumPersonal; void TestFSM(const TActorContext &ctx); public: - TTestChunkReserve(const TIntrusivePtr<TTestConfig> &cfg) + TTestChunkUnlock(const TIntrusivePtr<TTestConfig> &cfg) : TBaseTest(cfg) {} }; -class TTestCheckSpace : public TBaseTest { +class TTestChunkUnlockHarakiri : public TBaseTest { NPDisk::TOwner Owner; NPDisk::TOwnerRound OwnerRound; + ui32 TotalFree; void TestFSM(const TActorContext &ctx); public: - TTestCheckSpace(const TIntrusivePtr<TTestConfig> &cfg) + TTestChunkUnlockHarakiri(const TIntrusivePtr<TTestConfig> &cfg) : TBaseTest(cfg) {} }; -class TTestChunksLockByRange : public TBaseTest { - ui32 ChunksToBeLockedBegin; - ui32 ChunksToBeLockedEnd; +class TTestChunkUnlockRestart : public TBaseTest { + NPDisk::TOwner Owner; + NPDisk::TOwnerRound OwnerRound; + TActorId WhiteboardID; + TActorId NodeWardenId; void TestFSM(const TActorContext &ctx); public: - TTestChunksLockByRange(const TIntrusivePtr<TTestConfig> &cfg) + TTestChunkUnlockRestart(const TIntrusivePtr<TTestConfig> &cfg) : TBaseTest(cfg) {} }; -class TTestChunksLockUnlockReserve : public TBaseTest { +class TTestChunkReserve : public TBaseTest { + NPDisk::TOwner Owner; + NPDisk::TOwnerRound OwnerRound; + + void TestFSM(const TActorContext &ctx); +public: + TTestChunkReserve(const TIntrusivePtr<TTestConfig> &cfg) + : TBaseTest(cfg) + {} +}; + +class TTestCheckSpace : public TBaseTest { NPDisk::TOwner Owner; NPDisk::TOwnerRound OwnerRound; - ui32 ChunksToBeLockedCount; void TestFSM(const TActorContext &ctx); public: - TTestChunksLockUnlockReserve(const TIntrusivePtr<TTestConfig> &cfg) + TTestCheckSpace(const TIntrusivePtr<TTestConfig> &cfg) : TBaseTest(cfg) {} }; + class TTestHttpInfo : public TBaseTest { THttpRequest HttpRequest; NMonitoring::TMonService2HttpRequest MonService2HttpRequest; diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_base_test.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_base_test.h index d7d0cd3522..43c2f38a63 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_base_test.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_base_test.h @@ -79,6 +79,7 @@ protected: ui32 FreeChunks; ui32 TotalChunks; ui32 UsedChunks; + ui32 UnlockedChunks; TEvBlobStorage::EEv EventType; NKikimrProto::EReplyStatus Status; NPDisk::TOwner Owner; @@ -277,9 +278,8 @@ protected: ActTestFSM(ctx); } - - void Handle(NPDisk::TEvChunksLockResult::TPtr &ev, const TActorContext &ctx) { - NPDisk::TEvChunksLockResult &result = *(ev->Get()); + void Handle(NPDisk::TEvChunkLockResult::TPtr &ev, const TActorContext &ctx) { + NPDisk::TEvChunkLockResult &result = *(ev->Get()); LastResponse.Status = result.Status; LastResponse.EventType = (TEvBlobStorage::EEv)result.Type(); LastResponse.ChunkIds = result.LockedChunks; @@ -288,10 +288,11 @@ protected: ActTestFSM(ctx); } - void Handle(NPDisk::TEvChunksUnlockResult::TPtr &ev, const TActorContext &ctx) { - NPDisk::TEvChunksUnlockResult &result = *(ev->Get()); + void Handle(NPDisk::TEvChunkUnlockResult::TPtr &ev, const TActorContext &ctx) { + NPDisk::TEvChunkUnlockResult &result = *(ev->Get()); LastResponse.Status = result.Status; LastResponse.EventType = (TEvBlobStorage::EEv)result.Type(); + LastResponse.UnlockedChunks = result.UnlockedChunks; VERBOSE_COUT("Got " << result.ToString()); ActTestFSM(ctx); } @@ -372,8 +373,8 @@ public: HFunc(NPDisk::TEvChunkWriteResult, Handle); HFunc(NPDisk::TEvChunkReadResult, Handle); HFunc(NPDisk::TEvChunkReserveResult, Handle); - HFunc(NPDisk::TEvChunksLockResult, Handle); - HFunc(NPDisk::TEvChunksUnlockResult, Handle); + HFunc(NPDisk::TEvChunkLockResult, Handle); + HFunc(NPDisk::TEvChunkUnlockResult, Handle); HFunc(NPDisk::TEvHarakiriResult, Handle); HFunc(NPDisk::TEvSlayResult, Handle); HFunc(NPDisk::TEvYardControlResult, Handle); diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_yard.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_yard.cpp index 8aa8d23ef3..ba7353ad62 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_yard.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_yard.cpp @@ -323,25 +323,34 @@ YARD_UNIT_TEST(TestChunkContinuity9000) { Run<TTestChunk3WriteRead<9000>>(&tc, 1, MIN_CHUNK_SIZE); } -YARD_UNIT_TEST(TestChunkReserve) { +YARD_UNIT_TEST(TestChunkLock) { TTestContext tc(false, true); - Run<TTestChunkReserve>(&tc, 1, MIN_CHUNK_SIZE); + Run<TTestChunkLock>(&tc, 1, MIN_CHUNK_SIZE); } -YARD_UNIT_TEST(TestCheckSpace) { +YARD_UNIT_TEST(TestChunkUnlock) { TTestContext tc(false, true); - Run<TTestCheckSpace>(&tc, 1, MIN_CHUNK_SIZE); + Run<TTestChunkUnlock>(&tc, 1, MIN_CHUNK_SIZE); } -YARD_UNIT_TEST(TestChunksLockByRange) { +YARD_UNIT_TEST(TestChunkUnlockHarakiri) { TTestContext tc(false, true); - FillDeviceWithZeroes(&tc, MIN_CHUNK_SIZE); - Run<TTestChunksLockByRange>(&tc, 1, MIN_CHUNK_SIZE); + Run<TTestChunkUnlockHarakiri>(&tc, 1, MIN_CHUNK_SIZE); } -YARD_UNIT_TEST(TestChunksLockUnlockReserve) { +YARD_UNIT_TEST(TestChunkUnlockRestart) { TTestContext tc(false, true); - Run<TTestChunksLockUnlockReserve>(&tc, 1, MIN_CHUNK_SIZE); + Run<TTestChunkUnlockRestart>(&tc, 1, MIN_CHUNK_SIZE); +} + +YARD_UNIT_TEST(TestChunkReserve) { + TTestContext tc(false, true); + Run<TTestChunkReserve>(&tc, 1, MIN_CHUNK_SIZE); +} + +YARD_UNIT_TEST(TestCheckSpace) { + TTestContext tc(false, true); + Run<TTestCheckSpace>(&tc, 1, MIN_CHUNK_SIZE); } YARD_UNIT_TEST(TestHttpInfo) { diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_space_color.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_space_color.h index bdb0e0f152..0e1f77b8de 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_space_color.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_space_color.h @@ -64,4 +64,57 @@ inline NPDisk::TStatusFlags SpaceColorToStatusFlag(NKikimrBlobStorage::TPDiskSpa return flags; } +inline NKikimrBlobStorage::TPDiskSpaceColor::E ColorByName(const TString name) { + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + + if (name == "black") { + return TColor::BLACK; + } else if (name == "red") { + return TColor::RED; + } else if (name == "orange") { + return TColor::ORANGE; + } else if (name == "light_orange") { + return TColor::LIGHT_ORANGE; + } else if (name == "yellow") { + return TColor::YELLOW; + } else if (name == "light_yellow") { + return TColor::LIGHT_YELLOW; + } else if (name == "cyan") { + return TColor::CYAN; + } else { + return TColor::GREEN; + } +} + +inline TString TPDiskSpaceColor_Name(const NKikimrBlobStorage::TPDiskSpaceColor::E color) { + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + + switch (color) { + case TColor::BLACK: return "black"; + case TColor::RED: return "red"; + case TColor::ORANGE: return "orange"; + case TColor::LIGHT_ORANGE: return "light_orange"; + case TColor::YELLOW: return "yellow"; + case TColor::LIGHT_YELLOW: return "light_yellow"; + case TColor::CYAN: return "cyan"; + case TColor::GREEN: return "green"; + default: return "unknown"; + } +} + +inline TString TPDiskSpaceColor_HtmlCode(const NKikimrBlobStorage::TPDiskSpaceColor::E color) { + using TColor = NKikimrBlobStorage::TPDiskSpaceColor; + + switch (color) { + case TColor::BLACK: return "black"; + case TColor::RED: return "red"; + case TColor::ORANGE: return "orange"; + case TColor::LIGHT_ORANGE: return "#FFE500"; + case TColor::YELLOW: return "yellow"; + case TColor::LIGHT_YELLOW: return "#EEFF33"; + case TColor::CYAN: return "cyan"; + case TColor::GREEN: return "green"; + default: return "grey"; + } +} } diff --git a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp index fffc095ae7..ecb91e1b2b 100644 --- a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp +++ b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.cpp @@ -3,6 +3,8 @@ #include <ydb/core/util/stlog.h> #include <ydb/core/util/interval_set.h> +#include <ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_space_color.h> + namespace NKikimr { #ifdef _MSC_VER @@ -41,6 +43,7 @@ struct TPDiskMockState::TImpl { ui32 NextFreeChunk = 1; std::unordered_map<TString, ui32> Blocks; TIntervalSet<ui64> Corrupted; + NPDisk::TStatusFlags StatusFlags; TImpl(ui32 nodeId, ui32 pdiskId, ui64 pdiskGuid, ui64 size, ui32 chunkSize) : NodeId(nodeId) @@ -51,6 +54,7 @@ struct TPDiskMockState::TImpl { , TotalChunks(Size / ChunkSize) , AppendBlockSize(4096) , NextFreeChunk(1) + , StatusFlags(NPDisk::TStatusFlags{}) {} TImpl(const TImpl&) = default; @@ -209,6 +213,14 @@ struct TPDiskMockState::TImpl { } } } + + void SetStatusFlags(NPDisk::TStatusFlags flags) { + StatusFlags = flags; + } + + void SetStatusFlags(NKikimrBlobStorage::TPDiskSpaceColor::E spaceColor) { + StatusFlags = SpaceColorToStatusFlag(spaceColor); + } }; TPDiskMockState::TPDiskMockState(ui32 nodeId, ui32 pdiskId, ui64 pdiskGuid, ui64 size, ui32 chunkSize) @@ -242,6 +254,14 @@ void TPDiskMockState::TrimQuery() { Impl->TrimQuery(); } +void TPDiskMockState::SetStatusFlags(NKikimrBlobStorage::TPDiskSpaceColor::E spaceColor) { + Impl->SetStatusFlags(spaceColor); +} + +void TPDiskMockState::SetStatusFlags(NPDisk::TStatusFlags flags) { + Impl->SetStatusFlags(flags); +} + TPDiskMockState::TPtr TPDiskMockState::Snapshot() { auto res = MakeIntrusive<TPDiskMockState>(std::make_unique<TImpl>(*Impl)); res->Impl->AdjustRefs(); @@ -706,7 +726,7 @@ public: } NPDisk::TStatusFlags GetStatusFlags() { - return {}; + return Impl.StatusFlags; } STRICT_STFUNC(StateFunc, diff --git a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h index a09441f4ab..29b8871621 100644 --- a/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h +++ b/ydb/core/blobstorage/pdisk/mock/pdisk_mock.h @@ -25,6 +25,8 @@ namespace NKikimr { ui32 GetChunkSize() const; TIntervalSet<i64> GetWrittenAreas(ui32 chunkIdx) const; void TrimQuery(); + void SetStatusFlags(NKikimrBlobStorage::TPDiskSpaceColor::E spaceColor); + void SetStatusFlags(NPDisk::TStatusFlags flags); TPtr Snapshot(); // create a copy of PDisk whole state }; diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index 99d1520b82..1ffcbe49d4 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -713,6 +713,7 @@ message TFeatureFlags { optional bool EnableMoveIndex = 70 [default = false]; // enable http handle for self termination optional bool EnableFailureInjectionTermination = 71 [default = false]; + optional bool EnableChunkLocking = 72 [default = false]; } |