คลาส THPDFCoalescingRandomAccessSource
ครอบ THPDFRandomAccessSource ตัวใดก็ได้ด้วยแคช range แบบมีขอบเขตและ prefetch แบบอะซิงโครนัสที่รู้เรื่องการยกเลิก
การประกาศ
constructor Create(
ASource: THPDFRandomAccessSource;
OwnsSource: Boolean = False;
BlockSize: Integer = 262144;
MaxCacheBytes: Int64 = 2097152;
MaxEntryBytes: Int64 = 0;
MaxCacheEntries: Integer = 0;
AdaptiveAdmission: Boolean = True);
procedure PrefetchRange(Offset, Count: Int64);
procedure ObserveReadPattern(Offset: Int64; Count: Integer);
function TransferAt(Offset, Count: Int64;
Destination: TStream): Int64;
procedure CancelPrefetch;
function IsPrefetchActive: Boolean;
procedure ClearCache;
procedure ConfigureCacheAdmission(MaxCacheBytes,
MaxEntryBytes: Int64; MaxCacheEntries: Integer;
AdaptiveAdmission: Boolean = True);
procedure GetStatistics(out Statistics: THPDFRangeCacheStatistics);
property BlockSize: Integer;
property MaxCacheBytes: Int64;
property MaxEntryBytes: Int64;
property MaxCacheEntries: Integer;
property AdaptiveAdmissionEnabled: Boolean;
property AsyncPrefetchEnabled: Boolean;
property AdaptiveReadAheadEnabled: Boolean;
property MaxReadAheadBlocks: Integer;
property SequentialReadToleranceBytes: Integer;
การรวม range
- เมื่อแคช miss จะขยายเป็น block ที่จัดแนวแล้วครอบคลุมไบต์ที่ขอ ทำให้การอ่านที่อยู่ติดกันของ parser ใช้ request เดียวกันที่ backing store
- แคชบังคับลิมิตแยกกันทั้งแบบรวมไบต์ ต่อรายการ และจำนวนรายการแบบเสริม ส่วน range ที่ใหญ่เกินจะ bypass การเก็บรักษาไปเลย
- Adaptive admission ผสมลำดับ LRU กับ frequency sketch แบบมีขอบเขตเรื่องอายุ ทำให้การสแกนครั้งแรกอ่านตรงจากต้นทางโดยไม่ไล่ range ที่ร้อนกว่าออก
- เมื่อแหล่งที่เบาบางให้ block ที่ขยายแล้วไม่ได้ wrapper จะ fallback ไปใช้ช่วงที่ขอซึ่งมีของจริงเท่านั้น
- การเข้าถึงแหล่งถูกทำให้เป็นอนุกรม คลาสลูกที่มีอยู่จึงไม่จำเป็นต้องกลายเป็น thread safe
Prefetch แบบอะซิงโครนัสและการยกเลิก
PrefetchRange จัดคิว range พื้นหลังหนึ่งช่วงและแทนที่ request เก่าที่ไม่เกี่ยวข้องกัน
เมื่อแคช miss ใน foreground อยู่นอกช่วงที่ทำงานอยู่ จะยกเลิก worker ก่อนล็อกแหล่ง ทำให้ transport แบบ cooperative ยอมปล่อยให้ operation ที่มองเห็นได้ทำงานต่อได้ทันที
Override THPDFRandomAccessSource.ReadAtCancellable เพื่อดู THPDFCancellationToken ที่ส่งเข้ามาระหว่าง I/O เครือข่ายหรือ storage ส่วน implementation เดิมจะเช็กการยกเลิกทันทีก่อนและหลัง ReadAt
ตั้ง AsyncPrefetchEnabled เป็น False เมื่อนโยบาย transport ห้ามเข้าถึงจากพื้นหลัง
Read-ahead แบบปรับตัว
Stream ของ parser เรียก ObserveReadPattern หลังอ่านสำเร็จทุกครั้ง การอ่านไปข้างหน้าต่อเนื่องจะขยายหน้าต่าง read-ahead เป็น 1, 2, 4 และ 8 block ส่วนการ seek หรืออ่านย้อนกลับจะกด transport เชิงคาดเดาให้หยุดทันที
SequentialReadToleranceBytes ยอมรับช่องว่างข้างหน้าเล็กๆ ว่าเป็นการอ่านต่อเนื่องและค่าเริ่มต้น 4096 ไบต์ ส่วน MaxReadAheadBlocks จำกัดหน้าต่างแบบปรับตัวไว้ 1 ถึง 32 block ค่าเริ่มต้น 8
หน้าต่างที่มีผลจริงยังถูกจำกัดด้วย MaxCacheBytes ด้วย read-ahead จึงเกินความจุแคชที่ตั้งไว้แบบตั้งใจไม่ได้ และความมั่นใจว่าอ่านต่อเนื่องจะค่อยๆ ฟื้นหลังกระโดดแบบสุ่ม
ตั้ง AdaptiveReadAheadEnabled เป็น False หากต้องการ prefetch ครั้งละหนึ่ง block ตายตัวแต่ยังคง transport แบบอะซิงโครนัสไว้
สถิติ
TransferAt อ้างอิง cache block ที่เก็บไว้แล้วเขียนลงปลายทางโดยตรง ไม่ต้องจองหรือเติม read buffer ชั้นกลาง
THPDFRangeCacheStatistics รายงานจำนวนและไบต์ที่อ่านจากแหล่งจริง แคช hit กับ miss การรับเข้า ปฏิเสธ และไล่ออกของแคช การรับเข้า ปฏิเสธ และ aging ตามความถี่ request, เสร็จ และยกเลิกของ prefetch การอ่านแบบต่อเนื่องกับแบบสุ่ม prefetch ที่ถูกกด block read-ahead ปัจจุบันกับสูงสุด จำนวนและไบต์ของ direct transfer รวมถึงจำนวนและไบต์ range ที่อยู่ในแคชตอนนี้
ความเป็นเจ้าของ
เมื่อ OwnsSource เป็น True การทำลาย wrapper จะยกเลิกและรอ worker จบ คืน range ที่แคชไว้ แล้วคืนแหล่งที่ถูกครอบ