2525import org .apache .tsfile .encoding .decoder .Decoder ;
2626import org .apache .tsfile .encrypt .EncryptParameter ;
2727import org .apache .tsfile .encrypt .IDecryptor ;
28+ import org .apache .tsfile .enums .TSDataType ;
29+ import org .apache .tsfile .file .MetaMarker ;
2830import org .apache .tsfile .file .header .ChunkHeader ;
2931import org .apache .tsfile .file .header .PageHeader ;
3032import org .apache .tsfile .file .metadata .enums .EncryptionType ;
3335import org .apache .tsfile .read .reader .chunk .AbstractChunkReader ;
3436import org .apache .tsfile .read .reader .page .LazyLoadPageData ;
3537import org .apache .tsfile .read .reader .page .PageReader ;
38+ import org .apache .tsfile .utils .RamUsageEstimator ;
3639
3740import java .io .IOException ;
3841import java .io .Serializable ;
3942import java .nio .ByteBuffer ;
43+ import java .util .ArrayList ;
44+ import java .util .Collections ;
45+ import java .util .List ;
46+ import java .util .Objects ;
4047
4148import static org .apache .tsfile .file .metadata .enums .CompressionType .UNCOMPRESSED ;
4249
@@ -53,7 +60,8 @@ public SinglePageWholeChunkReader(Chunk chunk) throws IOException {
5360 this .chunkHeader = chunk .getHeader ();
5461 this .chunkDataBuffer = chunk .getData ();
5562 this .encryptParam = chunk .getEncryptParam ();
56- this .pageEstimatedMemoryUsageInBytes = calculatePageEstimatedMemoryUsageInBytes (chunk );
63+ this .pageEstimatedMemoryUsageInBytes =
64+ calculateMaxPageEstimatedMemoryUsageInBytesWithBatchData (chunk );
5765 initAllPageReaders ();
5866 }
5967
@@ -91,11 +99,190 @@ public long getCurrentPageEstimatedMemoryUsageInBytes() {
9199 public static long calculatePageEstimatedMemoryUsageInBytes (final Chunk chunk )
92100 throws IOException {
93101 final ByteBuffer chunkDataBuffer = chunk .getData ().duplicate ();
94- final PageHeader pageHeader =
95- PageHeader .deserializeFrom (chunkDataBuffer , (Statistics <? extends Serializable >) null );
102+ final PageHeader pageHeader = deserializePageHeader (chunkDataBuffer , chunk .getHeader ());
96103 return pageHeader .getUncompressedSize ();
97104 }
98105
106+ public static long calculateMaxPageEstimatedMemoryUsageInBytes (final Chunk chunk )
107+ throws IOException {
108+ final ByteBuffer chunkDataBuffer = chunk .getData ().duplicate ();
109+ long maxPageEstimatedMemoryUsageInBytes = 0 ;
110+ while (chunkDataBuffer .remaining () > 0 ) {
111+ final PageHeader pageHeader = deserializePageHeader (chunkDataBuffer , chunk .getHeader ());
112+ maxPageEstimatedMemoryUsageInBytes =
113+ Math .max (maxPageEstimatedMemoryUsageInBytes , pageHeader .getUncompressedSize ());
114+ skipCompressedPageData (chunkDataBuffer , pageHeader );
115+ }
116+ return maxPageEstimatedMemoryUsageInBytes ;
117+ }
118+
119+ public static long calculateMaxPageEstimatedMemoryUsageInBytesWithBatchData (final Chunk chunk )
120+ throws IOException {
121+ final List <Long > pageEstimatedMemoryUsageInBytesList =
122+ calculatePageEstimatedMemoryUsageInBytesWithBatchDataList (chunk );
123+ return pageEstimatedMemoryUsageInBytesList .isEmpty ()
124+ ? 0
125+ : pageEstimatedMemoryUsageInBytesList .get (0 );
126+ }
127+
128+ public static List <Long > calculatePageEstimatedMemoryUsageInBytesWithBatchDataList (
129+ final Chunk chunk ) throws IOException {
130+ final ByteBuffer chunkDataBuffer = chunk .getData ().duplicate ();
131+ final List <Long > pageEstimatedMemoryUsageInBytesList = new ArrayList <>();
132+ while (chunkDataBuffer .remaining () > 0 ) {
133+ final PageHeader pageHeader = deserializePageHeader (chunkDataBuffer , chunk .getHeader ());
134+ pageEstimatedMemoryUsageInBytesList .add (
135+ estimatePageMemoryUsageInBytesWithBatchData (
136+ pageHeader , chunk , Collections .singletonList (chunk .getHeader ().getDataType ())));
137+ skipCompressedPageData (chunkDataBuffer , pageHeader );
138+ }
139+ return toSuffixMaxList (pageEstimatedMemoryUsageInBytesList );
140+ }
141+
142+ static PageHeader deserializePageHeader (
143+ final ByteBuffer chunkDataBuffer , final ChunkHeader chunkHeader ) throws IOException {
144+ return isSinglePageChunk (chunkHeader )
145+ ? PageHeader .deserializeFrom (chunkDataBuffer , (Statistics <? extends Serializable >) null )
146+ : PageHeader .deserializeFrom (chunkDataBuffer , chunkHeader .getDataType ());
147+ }
148+
149+ static boolean isSinglePageChunk (final ChunkHeader chunkHeader ) {
150+ return (chunkHeader .getChunkType () & 0x3F ) == MetaMarker .ONLY_ONE_PAGE_CHUNK_HEADER ;
151+ }
152+
153+ static void skipCompressedPageData (
154+ final ByteBuffer chunkDataBuffer , final PageHeader pageHeader ) {
155+ chunkDataBuffer .position (chunkDataBuffer .position () + pageHeader .getCompressedSize ());
156+ }
157+
158+ static List <Long > toSuffixMaxList (final List <Long > pageEstimatedMemoryUsageInBytesList ) {
159+ long suffixMaxPageEstimatedMemoryUsageInBytes = 0 ;
160+ for (int i = pageEstimatedMemoryUsageInBytesList .size () - 1 ; i >= 0 ; --i ) {
161+ suffixMaxPageEstimatedMemoryUsageInBytes =
162+ Math .max (
163+ suffixMaxPageEstimatedMemoryUsageInBytes , pageEstimatedMemoryUsageInBytesList .get (i ));
164+ pageEstimatedMemoryUsageInBytesList .set (i , suffixMaxPageEstimatedMemoryUsageInBytes );
165+ }
166+ return pageEstimatedMemoryUsageInBytesList ;
167+ }
168+
169+ static long estimatePageMemoryUsageInBytesWithBatchData (
170+ final PageHeader timePageHeader ,
171+ final Chunk timeChunk ,
172+ final List <TSDataType > valueDataTypeList ) {
173+ return estimatePageMemoryUsageInBytesWithBatchData (
174+ timePageHeader .getUncompressedSize (),
175+ getPageRowCount (timePageHeader , timeChunk ),
176+ valueDataTypeList );
177+ }
178+
179+ static int getPageRowCount (final PageHeader pageHeader , final Chunk chunk ) {
180+ if (isSinglePageChunk (chunk .getHeader ())) {
181+ return Objects .isNull (chunk .getChunkStatistic ())
182+ ? 0
183+ : saturateToInt (chunk .getChunkStatistic ().getCount ());
184+ }
185+ return saturateToInt (pageHeader .getNumOfValues ());
186+ }
187+
188+ private static int saturateToInt (final long value ) {
189+ return (int ) Math .min (Integer .MAX_VALUE , value );
190+ }
191+
192+ static long estimatePageMemoryUsageInBytesWithBatchData (
193+ final long pageUncompressedSizeInBytes ,
194+ final int rowCount ,
195+ final List <TSDataType > valueDataTypeList ) {
196+ return pageUncompressedSizeInBytes
197+ + estimateBatchDataMemoryUsageInBytes (rowCount , valueDataTypeList );
198+ }
199+
200+ private static long estimateBatchDataMemoryUsageInBytes (
201+ final int rowCount , final List <TSDataType > valueDataTypeList ) {
202+ final int valueCount = valueDataTypeList .size ();
203+ final long segmentCount = Math .max (1 , (rowCount + 15L ) / 16 );
204+ long estimatedMemoryUsageInBytes = RamUsageEstimator .sizeOfLongArray (16 ) * segmentCount ;
205+
206+ if (valueCount == 1 ) {
207+ estimatedMemoryUsageInBytes +=
208+ estimateSingleValueArrayMemoryUsageInBytes (rowCount , valueDataTypeList .get (0 ));
209+ } else if (valueCount > 1 ) {
210+ estimatedMemoryUsageInBytes += RamUsageEstimator .sizeOfObjectArray (16 ) * segmentCount ;
211+ estimatedMemoryUsageInBytes +=
212+ (long ) rowCount
213+ * (RamUsageEstimator .sizeOfObjectArray (valueCount )
214+ + estimateVectorValueMemoryUsageInBytes (valueDataTypeList ));
215+ }
216+
217+ return estimatedMemoryUsageInBytes ;
218+ }
219+
220+ private static long estimateSingleValueArrayMemoryUsageInBytes (
221+ final int rowCount , final TSDataType dataType ) {
222+ final long segmentCount = Math .max (1 , (rowCount + 15L ) / 16 );
223+ if (Objects .isNull (dataType )) {
224+ return 0 ;
225+ }
226+
227+ switch (dataType ) {
228+ case BOOLEAN :
229+ return RamUsageEstimator .sizeOfBooleanArray (16 ) * segmentCount ;
230+ case INT32 :
231+ case DATE :
232+ return RamUsageEstimator .sizeOfIntArray (16 ) * segmentCount ;
233+ case INT64 :
234+ case TIMESTAMP :
235+ return RamUsageEstimator .sizeOfLongArray (16 ) * segmentCount ;
236+ case FLOAT :
237+ return RamUsageEstimator .sizeOfFloatArray (16 ) * segmentCount ;
238+ case DOUBLE :
239+ return RamUsageEstimator .sizeOfDoubleArray (16 ) * segmentCount ;
240+ case TEXT :
241+ case BLOB :
242+ case STRING :
243+ return RamUsageEstimator .sizeOfObjectArray (16 ) * segmentCount ;
244+ default :
245+ return 0 ;
246+ }
247+ }
248+
249+ private static long estimateVectorValueMemoryUsageInBytes (
250+ final List <TSDataType > valueDataTypeList ) {
251+ long estimatedMemoryUsageInBytes = 0 ;
252+ for (final TSDataType dataType : valueDataTypeList ) {
253+ if (Objects .isNull (dataType )) {
254+ continue ;
255+ }
256+
257+ estimatedMemoryUsageInBytes +=
258+ RamUsageEstimator .alignObjectSize (
259+ RamUsageEstimator .NUM_BYTES_OBJECT_HEADER
260+ + estimateTsPrimitiveTypeValueMemoryUsageInBytes (dataType ));
261+ }
262+ return estimatedMemoryUsageInBytes ;
263+ }
264+
265+ private static long estimateTsPrimitiveTypeValueMemoryUsageInBytes (final TSDataType dataType ) {
266+ switch (dataType ) {
267+ case BOOLEAN :
268+ return 1 ;
269+ case INT32 :
270+ case DATE :
271+ case FLOAT :
272+ return Integer .BYTES ;
273+ case INT64 :
274+ case TIMESTAMP :
275+ case DOUBLE :
276+ return Long .BYTES ;
277+ case TEXT :
278+ case BLOB :
279+ case STRING :
280+ return RamUsageEstimator .NUM_BYTES_OBJECT_REF ;
281+ default :
282+ return 0 ;
283+ }
284+ }
285+
99286 /////////////////////////////////////////////////////////////////////////////////////////////////
100287 // util methods
101288 /////////////////////////////////////////////////////////////////////////////////////////////////
0 commit comments