ref.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. #include "ref.h"
  2. #include "blob.h"
  3. #include <library/cpp/yt/malloc/malloc.h>
  4. #include <library/cpp/yt/misc/port.h>
  5. #include <library/cpp/yt/string/format.h>
  6. #include <util/system/info.h>
  7. #include <util/system/align.h>
  8. namespace NYT {
  9. ////////////////////////////////////////////////////////////////////////////////
  10. namespace NDetail {
  11. // N.B. We would prefer these arrays to be zero sized
  12. // but zero sized arrays are not supported in MSVC.
  13. const char EmptyRefData[1] = {0};
  14. char MutableEmptyRefData[1] = {0};
  15. } // namespace NDetail
  16. ////////////////////////////////////////////////////////////////////////////////
  17. class TBlobHolder
  18. : public TSharedRangeHolder
  19. {
  20. public:
  21. explicit TBlobHolder(TBlob&& blob)
  22. : Blob_(std::move(blob))
  23. { }
  24. // TSharedRangeHolder overrides.
  25. std::optional<size_t> GetTotalByteSize() const override
  26. {
  27. return Blob_.Capacity();
  28. }
  29. private:
  30. const TBlob Blob_;
  31. };
  32. ////////////////////////////////////////////////////////////////////////////////
  33. class TStringHolder
  34. : public TSharedRangeHolder
  35. {
  36. public:
  37. TStringHolder(TString&& string, TRefCountedTypeCookie cookie)
  38. : String_(std::move(string))
  39. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  40. , Cookie_(cookie)
  41. #endif
  42. {
  43. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  44. TRefCountedTrackerFacade::AllocateTagInstance(Cookie_);
  45. TRefCountedTrackerFacade::AllocateSpace(Cookie_, String_.length());
  46. #endif
  47. }
  48. ~TStringHolder()
  49. {
  50. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  51. TRefCountedTrackerFacade::FreeTagInstance(Cookie_);
  52. TRefCountedTrackerFacade::FreeSpace(Cookie_, String_.length());
  53. #endif
  54. }
  55. const TString& String() const
  56. {
  57. return String_;
  58. }
  59. // TSharedRangeHolder overrides.
  60. std::optional<size_t> GetTotalByteSize() const override
  61. {
  62. return String_.capacity();
  63. }
  64. private:
  65. const TString String_;
  66. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  67. const TRefCountedTypeCookie Cookie_;
  68. #endif
  69. };
  70. ////////////////////////////////////////////////////////////////////////////////
  71. template <class TDerived>
  72. class TAllocationHolderBase
  73. : public TSharedRangeHolder
  74. {
  75. public:
  76. ~TAllocationHolderBase()
  77. {
  78. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  79. TRefCountedTrackerFacade::FreeTagInstance(Cookie_);
  80. TRefCountedTrackerFacade::FreeSpace(Cookie_, Size_);
  81. #endif
  82. }
  83. TMutableRef GetRef()
  84. {
  85. return TMutableRef(static_cast<TDerived*>(this)->GetBegin(), Size_);
  86. }
  87. protected:
  88. size_t Size_;
  89. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  90. TRefCountedTypeCookie Cookie_;
  91. #endif
  92. void Initialize(
  93. size_t size,
  94. TSharedMutableRefAllocateOptions options,
  95. TRefCountedTypeCookie cookie)
  96. {
  97. Size_ = size;
  98. Cookie_ = cookie;
  99. if (options.InitializeStorage) {
  100. ::memset(static_cast<TDerived*>(this)->GetBegin(), 0, Size_);
  101. }
  102. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  103. TRefCountedTrackerFacade::AllocateTagInstance(Cookie_);
  104. TRefCountedTrackerFacade::AllocateSpace(Cookie_, Size_);
  105. #endif
  106. }
  107. };
  108. ////////////////////////////////////////////////////////////////////////////////
  109. class TDefaultAllocationHolder
  110. : public TAllocationHolderBase<TDefaultAllocationHolder>
  111. , public TWithExtraSpace<TDefaultAllocationHolder>
  112. {
  113. public:
  114. TDefaultAllocationHolder(
  115. size_t size,
  116. TSharedMutableRefAllocateOptions options,
  117. TRefCountedTypeCookie cookie)
  118. {
  119. if (options.ExtendToUsableSize) {
  120. if (auto usableSize = GetUsableSpaceSize(); usableSize != 0) {
  121. size = usableSize;
  122. }
  123. }
  124. Initialize(size, options, cookie);
  125. }
  126. char* GetBegin()
  127. {
  128. return static_cast<char*>(GetExtraSpacePtr());
  129. }
  130. // TSharedRangeHolder overrides.
  131. std::optional<size_t> GetTotalByteSize() const override
  132. {
  133. return Size_;
  134. }
  135. };
  136. ////////////////////////////////////////////////////////////////////////////////
  137. class TPageAlignedAllocationHolder
  138. : public TAllocationHolderBase<TPageAlignedAllocationHolder>
  139. {
  140. public:
  141. TPageAlignedAllocationHolder(
  142. size_t size,
  143. TSharedMutableRefAllocateOptions options,
  144. TRefCountedTypeCookie cookie)
  145. : Begin_(static_cast<char*>(::aligned_malloc(size, GetPageSize())))
  146. {
  147. Initialize(size, options, cookie);
  148. }
  149. ~TPageAlignedAllocationHolder()
  150. {
  151. ::free(Begin_);
  152. }
  153. char* GetBegin()
  154. {
  155. return Begin_;
  156. }
  157. // TSharedRangeHolder overrides.
  158. std::optional<size_t> GetTotalByteSize() const override
  159. {
  160. return AlignUp(Size_, GetPageSize());
  161. }
  162. private:
  163. char* const Begin_;
  164. };
  165. ////////////////////////////////////////////////////////////////////////////////
  166. TRef TRef::FromBlob(const TBlob& blob)
  167. {
  168. return TRef(blob.Begin(), blob.Size());
  169. }
  170. bool TRef::AreBitwiseEqual(TRef lhs, TRef rhs)
  171. {
  172. if (lhs.Size() != rhs.Size()) {
  173. return false;
  174. }
  175. if (lhs.Size() == 0) {
  176. return true;
  177. }
  178. return ::memcmp(lhs.Begin(), rhs.Begin(), lhs.Size()) == 0;
  179. }
  180. ////////////////////////////////////////////////////////////////////////////////
  181. TMutableRef TMutableRef::FromBlob(TBlob& blob)
  182. {
  183. return TMutableRef(blob.Begin(), blob.Size());
  184. }
  185. ////////////////////////////////////////////////////////////////////////////////
  186. TSharedRef TSharedRef::FromString(TString str, TRefCountedTypeCookie tagCookie)
  187. {
  188. auto holder = New<TStringHolder>(std::move(str), tagCookie);
  189. auto ref = TRef::FromString(holder->String());
  190. return TSharedRef(ref, std::move(holder));
  191. }
  192. TSharedRef TSharedRef::FromBlob(TBlob&& blob)
  193. {
  194. auto ref = TRef::FromBlob(blob);
  195. auto holder = New<TBlobHolder>(std::move(blob));
  196. return TSharedRef(ref, std::move(holder));
  197. }
  198. TSharedRef TSharedRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie)
  199. {
  200. if (!ref) {
  201. return {};
  202. }
  203. if (ref.Empty()) {
  204. return TSharedRef::MakeEmpty();
  205. }
  206. auto result = TSharedMutableRef::Allocate(ref.Size(), {.InitializeStorage = false}, tagCookie);
  207. ::memcpy(result.Begin(), ref.Begin(), ref.Size());
  208. return result;
  209. }
  210. std::vector<TSharedRef> TSharedRef::Split(size_t partSize) const
  211. {
  212. YT_VERIFY(partSize > 0);
  213. std::vector<TSharedRef> result;
  214. result.reserve(Size() / partSize + 1);
  215. auto sliceBegin = Begin();
  216. while (sliceBegin < End()) {
  217. auto sliceEnd = sliceBegin + partSize;
  218. if (sliceEnd < sliceBegin || sliceEnd > End()) {
  219. sliceEnd = End();
  220. }
  221. result.push_back(Slice(sliceBegin, sliceEnd));
  222. sliceBegin = sliceEnd;
  223. }
  224. return result;
  225. }
  226. ////////////////////////////////////////////////////////////////////////////////
  227. TSharedMutableRef TSharedMutableRef::Allocate(size_t size, TSharedMutableRefAllocateOptions options, TRefCountedTypeCookie tagCookie)
  228. {
  229. auto holder = NewWithExtraSpace<TDefaultAllocationHolder>(size, size, options, tagCookie);
  230. auto ref = holder->GetRef();
  231. return TSharedMutableRef(ref, std::move(holder));
  232. }
  233. TSharedMutableRef TSharedMutableRef::AllocatePageAligned(size_t size, TSharedMutableRefAllocateOptions options, TRefCountedTypeCookie tagCookie)
  234. {
  235. auto holder = New<TPageAlignedAllocationHolder>(size, options, tagCookie);
  236. auto ref = holder->GetRef();
  237. return TSharedMutableRef(ref, std::move(holder));
  238. }
  239. TSharedMutableRef TSharedMutableRef::FromBlob(TBlob&& blob)
  240. {
  241. auto ref = TMutableRef::FromBlob(blob);
  242. auto holder = New<TBlobHolder>(std::move(blob));
  243. return TSharedMutableRef(ref, std::move(holder));
  244. }
  245. TSharedMutableRef TSharedMutableRef::MakeCopy(TRef ref, TRefCountedTypeCookie tagCookie)
  246. {
  247. if (!ref) {
  248. return {};
  249. }
  250. if (ref.Empty()) {
  251. return TSharedMutableRef::MakeEmpty();
  252. }
  253. auto result = Allocate(ref.Size(), {.InitializeStorage = false}, tagCookie);
  254. ::memcpy(result.Begin(), ref.Begin(), ref.Size());
  255. return result;
  256. }
  257. ////////////////////////////////////////////////////////////////////////////////
  258. void FormatValue(TStringBuilderBase* builder, const TRef& ref, TStringBuf spec)
  259. {
  260. FormatValue(builder, TStringBuf{ref.Begin(), ref.End()}, spec);
  261. }
  262. void FormatValue(TStringBuilderBase* builder, const TMutableRef& ref, TStringBuf spec)
  263. {
  264. FormatValue(builder, TRef(ref), spec);
  265. }
  266. void FormatValue(TStringBuilderBase* builder, const TSharedRef& ref, TStringBuf spec)
  267. {
  268. FormatValue(builder, TRef(ref), spec);
  269. }
  270. void FormatValue(TStringBuilderBase* builder, const TSharedMutableRef& ref, TStringBuf spec)
  271. {
  272. FormatValue(builder, TRef(ref), spec);
  273. }
  274. size_t GetPageSize()
  275. {
  276. static const size_t PageSize = NSystemInfo::GetPageSize();
  277. return PageSize;
  278. }
  279. size_t RoundUpToPage(size_t bytes)
  280. {
  281. return AlignUp<size_t>(bytes, GetPageSize());
  282. }
  283. size_t GetByteSize(const TSharedRefArray& array)
  284. {
  285. size_t size = 0;
  286. if (array) {
  287. for (const auto& part : array) {
  288. size += part.Size();
  289. }
  290. }
  291. return size;
  292. }
  293. ////////////////////////////////////////////////////////////////////////////////
  294. i64 TSharedRefArray::ByteSize() const
  295. {
  296. i64 result = 0;
  297. if (*this) {
  298. for (const auto& part : *this) {
  299. result += part.Size();
  300. }
  301. }
  302. return result;
  303. }
  304. std::vector<TSharedRef> TSharedRefArray::ToVector() const
  305. {
  306. if (!Impl_) {
  307. return {};
  308. }
  309. return std::vector<TSharedRef>(Begin(), End());
  310. }
  311. TString TSharedRefArray::ToString() const
  312. {
  313. if (!Impl_) {
  314. return {};
  315. }
  316. TString result;
  317. size_t size = 0;
  318. for (const auto& part : *this) {
  319. size += part.size();
  320. }
  321. result.ReserveAndResize(size);
  322. char* ptr = result.begin();
  323. for (const auto& part : *this) {
  324. size += part.size();
  325. ::memcpy(ptr, part.begin(), part.size());
  326. ptr += part.size();
  327. }
  328. return result;
  329. }
  330. TSharedRefArray TSharedRefArray::MakeCopy(
  331. const TSharedRefArray& array,
  332. TRefCountedTypeCookie tagCookie)
  333. {
  334. TSharedRefArrayBuilder builder(
  335. array.Size(),
  336. array.ByteSize(),
  337. tagCookie);
  338. for (const auto& part : array) {
  339. auto partCopy = builder.AllocateAndAdd(part.Size());
  340. ::memcpy(partCopy.Begin(), part.Begin(), part.Size());
  341. }
  342. return builder.Finish();
  343. }
  344. ////////////////////////////////////////////////////////////////////////////////
  345. TSharedRefArrayBuilder::TSharedRefArrayBuilder(
  346. size_t size,
  347. size_t poolCapacity,
  348. TRefCountedTypeCookie tagCookie)
  349. : AllocationCapacity_(poolCapacity)
  350. , Impl_(TSharedRefArray::NewImpl(
  351. size,
  352. poolCapacity,
  353. tagCookie,
  354. size))
  355. , CurrentAllocationPtr_(Impl_->GetBeginAllocationPtr())
  356. { }
  357. void TSharedRefArrayBuilder::Add(TSharedRef part)
  358. {
  359. YT_ASSERT(CurrentPartIndex_ < Impl_->Size());
  360. Impl_->MutableBegin()[CurrentPartIndex_++] = std::move(part);
  361. }
  362. TMutableRef TSharedRefArrayBuilder::AllocateAndAdd(size_t size)
  363. {
  364. YT_ASSERT(CurrentPartIndex_ < Impl_->Size());
  365. YT_ASSERT(CurrentAllocationPtr_ + size <= Impl_->GetBeginAllocationPtr() + AllocationCapacity_);
  366. TMutableRef ref(CurrentAllocationPtr_, size);
  367. CurrentAllocationPtr_ += size;
  368. TSharedRangeHolderPtr holder(Impl_.Get(), false);
  369. TSharedRef sharedRef(ref, std::move(holder));
  370. Add(std::move(sharedRef));
  371. return ref;
  372. }
  373. TSharedRefArray TSharedRefArrayBuilder::Finish()
  374. {
  375. return TSharedRefArray(std::move(Impl_));
  376. }
  377. ////////////////////////////////////////////////////////////////////////////////
  378. } // namespace NYT