| 702 | } |
| 703 | |
| 704 | i64 TFileHandle::CountCache(i64 offset, i64 length) const noexcept { |
| 705 | #ifdef _linux_ |
| 706 | const i64 pageSize = NSystemInfo::GetPageSize(); |
| 707 | constexpr size_t vecSize = 512; // Fetch up to 2MiB at once |
| 708 | const i64 batchSize = vecSize * pageSize; |
| 709 | std::array<ui8, vecSize> vec; |
| 710 | void* ptr = nullptr; |
| 711 | i64 res = 0; |
| 712 | |
| 713 | if (!IsOpen()) { |
| 714 | return -1; |
| 715 | } |
| 716 | |
| 717 | if (!length) { |
| 718 | length = GetLength(); |
| 719 | length -= Min(length, offset); |
| 720 | } |
| 721 | |
| 722 | if (!length) { |
| 723 | return 0; |
| 724 | } |
| 725 | |
| 726 | const i64 begin = AlignDown(offset, pageSize); |
| 727 | const i64 end = AlignUp(offset + length, pageSize); |
| 728 | const i64 size = end - begin; |
| 729 | |
| 730 | /* |
| 731 | * Since fincode is not implemented yet use mmap and mincore. |
| 732 | * This is not so effective and scalable for frequent usage. |
| 733 | */ |
| 734 | ptr = ::mmap( |
| 735 | (caddr_t) nullptr, |
| 736 | size, |
| 737 | PROT_READ, |
| 738 | MAP_SHARED | MAP_NORESERVE, |
| 739 | Fd_, |
| 740 | begin); |
| 741 | if (MAP_FAILED == ptr) { |
| 742 | return -1; |
| 743 | } |
| 744 | |
| 745 | for (i64 base = begin; base < end; base += batchSize) { |
| 746 | const size_t batch = Min(vecSize, size_t((end - base) / pageSize)); |
| 747 | void* batchPtr = static_cast<caddr_t>(ptr) + (base - begin); |
| 748 | |
| 749 | if (::mincore(batchPtr, batch * pageSize, vec.data())) { |
| 750 | res = -1; |
| 751 | break; |
| 752 | } |
| 753 | |
| 754 | for (size_t i = 0; i < batch; i++) { |
| 755 | // count uptodate complete pages in cache |
| 756 | if (vec[i] & 1) { |
| 757 | res += pageSize; |
| 758 | } |
| 759 | } |
| 760 | |
| 761 | if (base == begin && (vec[0] & 1)) { |