ref.cpp 11 KB

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