| 830 | } |
| 831 | |
| 832 | FileSegmentsHolderPtr |
| 833 | FileCache::getOrSet( |
| 834 | const Key & key, |
| 835 | size_t offset, |
| 836 | size_t size, |
| 837 | size_t file_size, |
| 838 | const CreateFileSegmentSettings & create_settings, |
| 839 | size_t file_segments_limit, |
| 840 | const OriginInfo & origin_info, |
| 841 | std::optional<size_t> boundary_alignment_) |
| 842 | { |
| 843 | ProfileEventTimeIncrement<Microseconds> watch(ProfileEvents::FilesystemCacheGetOrSetMicroseconds); |
| 844 | |
| 845 | assertInitialized(); |
| 846 | |
| 847 | size_t initial_range_right_offset = (file_size ? std::min(offset + size, file_size) : offset + size) - 1; |
| 848 | FileSegment::Range initial_range(offset, initial_range_right_offset); |
| 849 | /// result_range is initial range, which will be adjusted according to |
| 850 | /// 1. aligned_offset, aligned_end_offset |
| 851 | /// 2. max_file_segments_limit |
| 852 | FileSegment::Range result_range = initial_range; |
| 853 | |
| 854 | const size_t alignment = boundary_alignment_.value_or(boundary_alignment); |
| 855 | const auto aligned_offset = FileCacheUtils::roundDownToMultiple(initial_range.left, alignment); |
| 856 | auto aligned_end_offset = (file_size |
| 857 | ? std::min(FileCacheUtils::roundUpToMultiple(initial_range.right + 1, alignment), file_size) |
| 858 | : FileCacheUtils::roundUpToMultiple(initial_range.right + 1, alignment)) - 1; |
| 859 | |
| 860 | chassert(aligned_offset <= initial_range.left); |
| 861 | chassert(aligned_end_offset >= initial_range.right); |
| 862 | |
| 863 | auto locked_key = metadata.lockKeyMetadata( |
| 864 | key, CacheMetadata::KeyNotFoundPolicy::CREATE_EMPTY, origin_info); |
| 865 | |
| 866 | /// Get all segments which intersect with the given range. |
| 867 | auto file_segments = getImpl(*locked_key, initial_range, file_segments_limit); |
| 868 | |
| 869 | if (file_segments_limit) |
| 870 | { |
| 871 | chassert(file_segments.size() <= file_segments_limit); |
| 872 | if (file_segments.size() == file_segments_limit) |
| 873 | result_range.right = aligned_end_offset = file_segments.back()->range().right; |
| 874 | } |
| 875 | |
| 876 | /// Check case if we have uncovered prefix, e.g. |
| 877 | /// |
| 878 | /// [_______________] |
| 879 | /// ^ ^ |
| 880 | /// range.left range.right |
| 881 | /// [___] [__________] <-- current cache (example) |
| 882 | /// [ ] |
| 883 | /// ^----^ |
| 884 | /// uncovered prefix. |
| 885 | const bool has_uncovered_prefix = file_segments.empty() || result_range.left < file_segments.front()->range().left; |
| 886 | |
| 887 | if (aligned_offset < result_range.left && has_uncovered_prefix) |
| 888 | { |
| 889 | auto prefix_range = FileSegment::Range( |