ข้ามไปยังเนื้อหา

สัญญาสถาปัตยกรรมแคชการสแกนระบบไฟล์

เอกสารนี้กำหนดสัญญาปัจจุบันสำหรับแคชการสแกนระบบไฟล์ร่วมที่ถูกใช้งานใน Rust (crates/pi-natives/src/fs_cache.rs) และถูกเรียกใช้โดย API การค้นพบ/ค้นหาแบบเนทีฟที่เปิดเผยต่อ packages/coding-agent

แคชจัดเก็บรายการรายการสแกนไดเรกทอรีแบบเต็ม (GlobMatch[]) โดยใช้ขอบเขตการสแกนและนโยบายการข้ามผ่านเป็นคีย์ จากนั้นให้การดำเนินการระดับสูงขึ้น (การกรอง glob, การให้คะแนนแบบ fuzzy, การเลือกไฟล์สำหรับ grep) ทำงานบนรายการที่แคชไว้เหล่านั้น

เป้าหมายหลัก:

  • หลีกเลี่ยงการเดินผ่านระบบไฟล์ซ้ำสำหรับการเรียกค้นพบ/ค้นหาที่ซ้ำกัน
  • รักษาความสอดคล้องกันระหว่าง glob, fuzzyFind, และ grep เมื่อใช้นโยบายการสแกนเดียวกัน
  • อนุญาตให้มีการกู้คืนความเก่าของข้อมูลอย่างชัดเจนสำหรับผลลัพธ์ว่างเปล่า และการทำให้ไม่ถูกต้องอย่างชัดเจนหลังจากการเปลี่ยนแปลงไฟล์
  • การใช้งานแคชและนโยบาย: crates/pi-natives/src/fs_cache.rs
  • ผู้เรียกใช้แบบเนทีฟ:
    • crates/pi-natives/src/glob.rs
    • crates/pi-natives/src/fd.rs (fuzzyFind)
    • crates/pi-natives/src/grep.rs
  • การผูกและส่งออก JS:
    • packages/natives/src/glob/index.ts (invalidateFsScanCache)
    • packages/natives/src/glob/types.ts
    • packages/natives/src/grep/types.ts
  • ตัวช่วยการทำให้ไม่ถูกต้องจากการกลายพันธุ์ของ coding-agent:
    • packages/coding-agent/src/tools/fs-cache-invalidation.ts

แต่ละรายการใช้คีย์ตาม:

  • เส้นทางไดเรกทอรี root ที่ถูก canonicalize แล้ว
  • บูลีน include_hidden
  • บูลีน use_gitignore

ผลที่ตามมา:

  • การสแกนแบบซ่อนและไม่ซ่อน ไม่แชร์ รายการ
  • การสแกนที่เคารพ gitignore และการสแกนที่ปิดใช้งาน ignore ไม่แชร์ รายการ
  • ผู้เรียกใช้ต้องส่งความหมายที่เสถียรสำหรับพฤติกรรม hidden/gitignore; การเปลี่ยนแฟล็กใดแฟล็กหนึ่งจะสร้างพาร์ติชันแคชที่แตกต่างออกไป

การรวม node_modules ไม่อยู่ ในคีย์แคช แคชจัดเก็บรายการที่รวม node_modules ไว้ด้วย โดยการกรองต่อผู้เรียกใช้จะถูกใช้หลังการดึงข้อมูล

การเติมแคชใช้ตัวเดินที่เป็นแบบกำหนดได้ (ignore::WalkBuilder) ที่กำหนดค่าโดย include_hidden และ use_gitignore:

  • follow_links(false)
  • เรียงลำดับตามเส้นทางไฟล์
  • .git จะถูกข้ามเสมอ
  • node_modules จะถูกรวบรวมเสมอในขณะสแกนแคช (และอาจกรองออกในภายหลัง)
  • ประเภทไฟล์ + mtime ของรายการจะถูกจับภาพผ่าน symlink_metadata

รากการค้นหาจะถูกแก้ไขโดย resolve_search_path:

  • เส้นทางสัมพัทธ์จะถูกแก้ไขตาม cwd ปัจจุบัน
  • เป้าหมายต้องเป็นไดเรกทอรีที่มีอยู่
  • รากจะถูก canonicalize เมื่อเป็นไปได้

นโยบายส่วนกลาง (กำหนดค่าได้ผ่านสภาพแวดล้อม):

  • FS_SCAN_CACHE_TTL_MS (ค่าเริ่มต้น 1000)
  • FS_SCAN_EMPTY_RECHECK_MS (ค่าเริ่มต้น 200)
  • FS_SCAN_CACHE_MAX_ENTRIES (ค่าเริ่มต้น 16)

พฤติกรรม:

  • get_or_scan(...)
    • หาก TTL เป็น 0: ข้ามแคชโดยสิ้นเชิง, สแกนใหม่เสมอ (cache_age_ms = 0)
    • เมื่อแคชถูกต้องภายใน TTL: คืนรายการที่แคชไว้ + cache_age_ms ที่ไม่ใช่ศูนย์
    • เมื่อแคชหมดอายุ: ขับรายการออก, สแกนใหม่, จัดเก็บรายการใหม่
  • การบังคับใช้จำนวนรายการสูงสุดใช้การขับออกแบบเก่าที่สุดก่อนตาม created_at

การตรวจสอบซ้ำเร็วสำหรับผลลัพธ์ว่าง (แยกจากการถูกต้องปกติ)

หัวข้อที่มีชื่อว่า “การตรวจสอบซ้ำเร็วสำหรับผลลัพธ์ว่าง (แยกจากการถูกต้องปกติ)”

การถูกต้องของแคชปกติ:

  • การถูกต้องของแคชภายใน TTL จะคืนรายการที่แคชไว้และไม่ทำอะไรเพิ่มเติม

การตรวจสอบซ้ำเร็วสำหรับผลลัพธ์ว่าง:

  • นี่คือนโยบาย ฝั่งผู้เรียกใช้ ที่ใช้ ScanResult.cache_age_ms
  • หากผลลัพธ์ที่กรอง/ค้นหาแล้วว่างเปล่าและอายุการสแกนที่แคชมีอย่างน้อย empty_recheck_ms(), ผู้เรียกใช้จะทำ force_rescan(...) หนึ่งครั้งและลองใหม่
  • มีจุดประสงค์เพื่อลดผลลัพธ์เชิงลบที่เก่าเมื่อไฟล์ถูกเพิ่มล่าสุดแต่แคชยังอยู่ภายใน TTL

ผู้เรียกใช้ปัจจุบัน:

  • glob: ตรวจสอบซ้ำเมื่อการจับคู่ที่กรองแล้วว่างเปล่าและอายุการสแกนเกินขีดกำหนด
  • fuzzyFind (fd.rs): ตรวจสอบซ้ำเฉพาะเมื่อการค้นหาไม่ว่างเปล่าและการจับคู่ที่ให้คะแนนแล้วว่างเปล่า
  • grep: ตรวจสอบซ้ำเมื่อรายการไฟล์ผู้สมัครที่เลือกว่างเปล่า

แคชเป็นแบบเลือกเปิดใช้งานบน API ที่เปิดเผยทั้งหมด (cache?: boolean, ค่าเริ่มต้น false)

ค่าเริ่มต้นปัจจุบันใน API แบบเนทีฟ:

  • glob: hidden=false, gitignore=true, cache=false
  • fuzzyFind: hidden=false, gitignore=true, cache=false
  • grep: hidden=true, cache=false, และการสแกนแคชจะใช้ use_gitignore=true เสมอ

ผู้เรียกใช้ coding-agent ในปัจจุบัน:

  • การค้นพบผู้สมัครที่กล่าวถึงปริมาณสูงเปิดใช้งานแคช:
    • packages/coding-agent/src/utils/file-mentions.ts
    • โปรไฟล์: hidden=true, gitignore=true, includeNodeModules=true, cache=true
  • การผสานรวม grep ระดับเครื่องมือในปัจจุบันปิดใช้งานแคชการสแกน (cache: false):
    • packages/coding-agent/src/tools/grep.ts

จุดเข้าการทำให้ไม่ถูกต้องแบบเนทีฟ:

  • invalidateFsScanCache(path?: string)
    • ด้วย path: ลบรายการแคชที่รากเป็น prefix ของเส้นทางเป้าหมาย
    • ไม่มี path: ล้างรายการแคชการสแกนทั้งหมด

รายละเอียดการจัดการเส้นทาง:

  • เส้นทางการทำให้ไม่ถูกต้องแบบสัมพัทธ์จะถูกแก้ไขตาม cwd
  • การทำให้ไม่ถูกต้องจะพยายาม canonicalize
  • หากเป้าหมายไม่มีอยู่ (เช่น ถูกลบ), ทางเลือกสำรองจะ canonicalize ไดเรกทอรีหลักและต่อชื่อไฟล์กลับเข้าไปเมื่อเป็นไปได้
  • ซึ่งรักษาพฤติกรรมการทำให้ไม่ถูกต้องสำหรับการสร้าง/ลบ/เปลี่ยนชื่อ ที่ด้านใดด้านหนึ่งอาจไม่มีอยู่

ความรับผิดชอบของกระบวนการกลายพันธุ์ของ coding-agent

หัวข้อที่มีชื่อว่า “ความรับผิดชอบของกระบวนการกลายพันธุ์ของ coding-agent”

โค้ด coding-agent ต้องทำให้ไม่ถูกต้องหลังจากการกลายพันธุ์ระบบไฟล์ที่สำเร็จ

ตัวช่วยกลาง:

  • invalidateFsScanAfterWrite(path)
  • invalidateFsScanAfterDelete(path)
  • invalidateFsScanAfterRename(oldPath, newPath) (ทำให้ไม่ถูกต้องทั้งสองด้านเมื่อเส้นทางแตกต่างกัน)

จุดเรียกใช้เครื่องมือการกลายพันธุ์ปัจจุบัน:

  • packages/coding-agent/src/tools/write.ts
  • packages/coding-agent/src/patch/index.ts (กระบวนการ hashline/patch/replace)

กฎ: หากกระบวนการใดกลายพันธุ์เนื้อหาหรือตำแหน่งของระบบไฟล์และข้ามตัวช่วยเหล่านี้ ข้อบกพร่องจากความเก่าของแคชเป็นสิ่งที่คาดหวังได้

เมื่อนำการใช้งานแคชมาใช้ในเส้นทางสแกน/ค้นหาใหม่:

  1. ใช้อินพุตนโยบายการสแกนที่เสถียร

    • กำหนดความหมาย hidden/gitignore ก่อน
    • ส่งค่าเหล่านั้นอย่างสม่ำเสมอไปยัง get_or_scan/force_rescan เพื่อให้พาร์ติชันแคชเป็นไปตามที่ตั้งใจ
  2. ถือว่าข้อมูลแคชถูกกรองล่วงหน้าเฉพาะตามนโยบายการข้ามผ่านเท่านั้น

    • ใช้การกรองเฉพาะเครื่องมือ (รูปแบบ glob, ตัวกรองประเภท, กฎ node_modules) หลังการดึงข้อมูล
    • อย่าสมมติว่ารายการที่แคชไว้สะท้อนตัวกรองระดับสูงของคุณแล้ว
  3. ใช้งานการตรวจสอบซ้ำเร็วสำหรับผลลัพธ์ว่างเฉพาะสำหรับความเสี่ยงผลลัพธ์เชิงลบที่เก่าเท่านั้น

    • ใช้ scan.cache_age_ms >= empty_recheck_ms()
    • ลองใหม่หนึ่งครั้งด้วย force_rescan(..., store=true, ...)
    • แยกเส้นทางนี้ออกจากตรรกะการถูกต้องของแคชปกติ
  4. เคารพโหมดไม่ใช้แคชอย่างชัดเจน

    • เมื่อผู้เรียกใช้ปิดใช้งานแคช ให้เรียก force_rescan(..., store=false, ...)
    • อย่าเติมแคชร่วมในเส้นทางคำขอแบบไม่ใช้แคช
  5. เชื่อมต่อการทำให้ไม่ถูกต้องจากการกลายพันธุ์สำหรับเส้นทางการเขียนใหม่ทุกเส้นทาง

    • หลังจากการเขียน/แก้ไข/ลบ/เปลี่ยนชื่อที่สำเร็จ ให้เรียกตัวช่วยการทำให้ไม่ถูกต้องของ coding-agent
    • สำหรับการเปลี่ยนชื่อ/ย้าย ให้ทำให้ไม่ถูกต้องทั้งเส้นทางเก่าและใหม่
  6. อย่าเพิ่มปุ่มปรับ TTL ต่อการเรียกใช้

    • สัญญาปัจจุบันเป็นนโยบายส่วนกลางเท่านั้น (กำหนดค่าผ่านสภาพแวดล้อม), ไม่มีการแทนที่ TTL ต่อคำขอ
  • ขอบเขตแคชเป็นในหน่วยความจำเฉพาะกระบวนการ (DashMap) ไม่มีการคงอยู่ข้ามการรีสตาร์ทกระบวนการ
  • แคชจัดเก็บรายการการสแกน ไม่ใช่ผลลัพธ์เครื่องมือขั้นสุดท้าย
  • glob/fuzzyFind/grep แชร์รายการการสแกนเฉพาะเมื่อมิติคีย์ (root, hidden, gitignore) ตรงกัน
  • .git จะถูกยกเว้นเสมอในเวลารวบรวมการสแกน โดยไม่คำนึงถึงตัวเลือกของผู้เรียกใช้