זהות שורה יציבה בלי heRef, וגארד נגד patch דלתא גדול מדי - #28
Conversation
|
שורה תחתונה: לא — ה־PR אינו חסר סיכון, ובמצבו הנוכחי לא הייתי מאשר את PR #28. מצד אוצריא, דיווחי טעויות אינם נשברים ישירות; אבל יש באג ממשי במיגרציית מזהי השורות שעלול לייצר DB שגוי, ואז בעקיפין לפגוע גם בדיווחים, בקישורים ובתוכן. דיווחי טעויות בספרבדקתי את שני מסלולי הדיווח:
גם הנתונים האישיים העיקריים אינם תלויים ב־
לכן: בהנחה שה־DB שנוצר תקין, החלפת המפתח מ־ אבל יש באג חוסם במחוללבמיגרציה הישנה והחדשה משתמשים באותה מפה mutable של
הבעיה נמצאת בשילוב בין החיפוש הרגיל לבין וזה לא בהכרח יכשיל את הבנייה בקול: הכנסת השורות משתמשת ב־ בצד אוצריא התוצאות האפשריות הן:
זה לבדו מצדיק Request changes. התיקון הנכון הוא לשמור snapshot בלתי־משתנה של מפת המפתחות הישנה, ולבנות מפה חדשה ונפרדת; בנוסף צריך invariant שמוודא שכל ID מוקצה לכל היותר לשורה אחת בבנייה הנוכחית. כדאי גם להחליף דיווח שגיאות טכני של העדכוןבמסלול העדכון של אוצריא לא מצאתי בליעה חדשה של הכשל העיקרי:
מסלול הטיפול בשגיאות, כתיבה ל־errors.txt. שתי הסתייגויות:
עוד סיכונים ממשיים
אימות שעשיתי בצד אוצריאעל שילוב אוצריא עם updater בקומיט
לכן המסקנה המדויקת היא:
|
מפתח השורה של ספריא היה sha1("REF:"+heRef), ולכן שינוי גורף ב-heRef (4e286b9, פסיק אחרי שם הספר) חידש את ה-id של 1.56M שורות ו-5.27M קישורים ב-5,128 ספרים, ו-patch v26→v27 תפח ל-2.4GB פרוסים (לעומת 7–43MB בעבר). המפתח עכשיו sha1("CT:"+rawSegment): התוכן הגולמי לפני קידומות הפסוק המוזרקות, עם occurrenceIdx לכפילויות תוכן בספר. heRef נשאר עמודה מתעדכנת רגילה.
מעבר בלי renumbering: shim מבודד (LegacyLineKey, LineOccurrenceCounter) מנסה לכל שורה את המפתח הישן ב-buildstate של הזרע, מעביר את ה-id למפתח החדש (remove + putIfAbsent) ומדווח מטריקת מעבר; מעל 1% החמצות נרשמת אזהרה. הבנייה הראשונה אחרי המיזוג חייבת לרוץ על כל הספרים, ומומלץ להריץ קודם delta-real-diff-test עם baseline upstream/otzaria.
PatchSizeGuard: עוגן ש-patch שלו פרוס מעל 0.5 מגודל ה-DB החדש מדולג דרך מסלול .unpatchable הקיים (טוקן oversized-delta); כשכל העוגנים מדולגים ה-release מתפרסם full-only עם אזהרה במקום להיכשל. ה-workflows של האימות מקבלים יחס 1000 כי הם בודקים מכניקה. הגארד הוא רשת ביטחון בלבד; אפליקציית אוצריא מסמנת דלתא כבדה כבר ב-0.25 ומשאירה את הבחירה למשתמש.
אין שינוי בסכמת ה-DB, בפורמט ה-patch, במניפסט או ב-buildstate — לקוחות קיימים ממשיכים לעבוד מול הארטיפקטים החדשים. רקע: Otzaria/otzaria#1211.
ה-shim קרא מאותה מפה חיה שהבנייה כותבת לה, ולכן שורה A (עם heRef) שתפסה את CT:X#0 ושורה B (בלי heRef) שמפתח ה-legacy שלה הוא אותו CT:X#0 קיבלו את אותו id, ו-INSERT OR IGNORE בלע את השנייה בשקט. התיקון: המיגרציה קוראת רק מ-snapshot בלתי משתנה של ה-build_state הישן; פנקס id→מפתח לבנייה הנוכחית מוודא שמזהה שכבר הוקצה לשורה אחרת לא יוצא שוב (נופל ל-id חדש, נספר ב-legacyLineKeyCollisions); הקצאה ישירה של אותו id לשני מפתחות מפילה את הבנייה במקום להפיל שורה. ב-snapshotTo נמחקים מפתחות legacy שנותרו לספרים שעובדו. שתי בדיקות חדשות: התרחיש מהביקורת, ו-seed פגום שמפיל את הבנייה.
9e4611f to
5dda924
Compare
|
תודה, הביקורת צדקה ותוקן בקומיט 5dda924 (הענף גם עבר ריבייס מול התיקון: המיגרציה קוראת רק מ-snapshot בלתי משתנה של ה-build_state הישן, ופנקס id→מפתח לבנייה הנוכחית מוודא שמזהה שכבר הוקצה לשורה אחרת לא יוצא שוב. בתרחיש שתיארת, B מקבלת id חדש (נספר ב-
נותר פתוח: גארד 0.5 לא היה תופס את v27 (32%–40%). ההצעה: 0.3 בשרת ו-0.15 בלקוח, או להשאיר. וכן בדיקת end-to-end על DB אמיתי ( |
התלבטות: להשאיר את ה-shim או להסיר אותוה- בלי ה-shim, בבנייה הראשונה כל שורה של ספריא מקבלת id חדש. זה בדיוק מה שקרה ב-v27 בגלל הפסיק ב-heRef, רק הפעם במכוון ופעם אחת.
להשאיר: v28 יוצא כדלתא רגילה לכולם. המחיר: קוד מעבר שצריך למחוק אחר כך, ואותו סוג באג שכבר תפסנו פעם אחת (מתוקן ומכוסה בבדיקות). להסיר: PR פשוט בהרבה, בלי מסלול מיגרציה בכלל. המחיר: v28 יהיה הורדה מלאה של 1.4GB לכל המשתמשים, כולל ברשת איטית. אחרי v28 המזהים יציבים והדלתאות חוזרות להיות קטנות. הנטייה שלי: להסיר, כי מחיר חד-פעמי ידוע עדיף על קוד מעבר שנשאר. אבל זו החלטת מוצר, לא טכנית, ולכן לא שיניתי כלום עד להחלטה. |
|
אימות end-to-end מלא עבר על head 0cfa140 מול baseline 09f60c3, עם הקלטים המקובעים של ריצת production 34024655297.
שתי ריצות האימות המרוחקות המיותרות (production runner, server-2) בוטלו לאחר שהאימות המקומי המלא נתן תוצאה מכרעת. |
מה
sha1("REF:"+heRef)ל-sha1("CT:"+rawSegment): התוכן הגולמי לפני קידומות הפסוק המוזרקות ((א), תוויות דף), עםoccurrenceIdxלכפילויות תוכן בתוך הספר. heRef נשאר עמודה מתעדכנת רגילה שזורמת ב-upsert_line.LegacyLineKey.kt,LineOccurrenceCounter.kt,InMemoryIdAllocator.migrateLegacyLineKey): לכל שורה שהמפתח החדש שלה חסר מנוסה המפתח הישן מתוך snapshot בלתי־משתנה של ה-buildstate של הזרע, וה-id נרשם במפה החדשה רק אם טרם הוקצה לשורה אחרת. היבואן מחזיק שני מוני occurrence במהלך המעבר. סיכום המעבר נרשם (מפתחות בזרע / הוגרו / ids טריים), ומעל 1% החמצות נרשמת אזהרה. ה-shim מיועד למחיקה אחרי בנייה מלאה אחת מוצלחת.PatchSizeGuard— עוגן ש-patch שלו פרוס מעלDEFAULT_MAX_DELTA_UNCOMPRESSED_RATIO = 0.30מגודל ה-DB החדש מדולג דרך מסלול.unpatchableהקיים (טוקןoversized-delta), לפני אימות ודחיסה. ב-manual-generate-release.yml: כשכל העוגנים דולגו בגלל הגארד, ה-release מתפרסם full-only עם::warning::במקום להיכשל; כשל מבני אמיתי עדיין מפיל. ה-workflows של האימות מקבלים-PmaxDeltaUncompressedRatio=1000(בודקים מכניקה, לא כלכלה).DELTA_UPDATE_WORKFLOW.md,LINKER_DELTA_PLAN.md.למה
Otzaria/otzaria#1211. נמדד על
patch-v26-v27:upsert_line1,558,787 ו-delete_line1,556,251 עם אפס חפיפת מזהים, ב-5,128 ספרים;upsert_link/delete_link5.27M כל אחת; סה"כ 2.4GB פרוסים לצעד גרסה יחיד (לעומת 7–43MB דחוסים ב-releases קודמים). הסיבה: 4e286b9 שינה heRef לכל שורה בסכמה הפשוטה, וכל שורה קיבלה id חדש עם קסקדה ל-link/line_toc/version_line. לקוחות החילו 3GB במשך שעה בלי חיווי.הגארד הוא רשת ביטחון בלבד ללקוחות שאין להם דיאלוג בחירה. אפליקציית אוצריא (PR נלווה) מסמנת דלתא כבדה כבר ב-0.25 ומשאירה את הבחירה למשתמש, כי ברשת איטית 585MB עדיפים על 1.4GB.
תיקון בעקבות הביקורת (קומיט 5dda924) + ריבייס מול
otzariaהביקורת צדקה: ה-shim קרא מאותה מפה חיה שהבנייה כותבת לה, ולכן שורה A (עם heRef, תוכן X) שתפסה את
CT:X#0ושורה B (בלי heRef) שמפתח ה-legacy שלה הוא אותוCT:X#0קיבלו את אותו id, ו-INSERT OR IGNOREהיה בולע את השנייה בשקט.seedLines).legacyLineKeyCollisions(מודפס בסיכום הבנייה).IllegalStateExceptionבמקום להפיל שורה.snapshotToמוחק מפתחות legacy שנותרו לספרים שעובדו בבנייה, כך שהם לא מזריעים בנייה עתידית.LegacyLineKeyMigrationTest: התרחיש מהביקורת בדיוק (ids שונים, snapshot נקי, בנייה שלישית יציבה), ו-seed פגום שמפיל את הבנייה.INSERT OR IGNOREב-LineQueries.sqלא שונה בכוונה: הוא משרת גם מסלולים אחרים, והאינווריאנט נאכף עכשיו בנקודת ההקצאה, לפני שה-insert בכלל רואה כפילות.הריבייס מול
otzaria(09f60c3):produce_anchorעבר ב-upstream ל-.github/scripts/patch_fan_lib.sh, ולכןSKIP_DIR/record_skipושלוש קריאות הרישום הועברו לשם; הבדיקה בחוזה קוראת מה-lib. אין שינוי בהתנהגות.תיקונים נוספים בעקבות הביקורת (קומיטים 40b7005, 0cfa140)
cleanSefariaLineשמרה בטעות את הקידומת בתוך המפתח הטבעי; הוספת שורה לפניה הייתה משנה את ה-id. כעת מצב הניקוי ואורך הקידומת מקודדים יחד: מפתח השורה מסיר את הקידומת, אך עוגני תווים עדיין נדחים כלא־מדויקים. נוספה בדיקת רגרסיה דרךSefariaBookPayloadReaderהאמיתי עם<br>והזזת(א)ל-(ב).תאימות
אין שינוי בסכמת ה-DB, בפורמט ה-patch, במניפסט או בסכמת ה-buildstate (
CURRENT_VERSIONנשאר 1). לקוחות קיימים ממשיכים לעבוד מול הארטיפקטים החדשים.לפני ה-release הראשון (חשוב)
delta-real-diff-test.ymlעםbaseline_ref = upstream/otzaria(בונה v1 בקוד הישן ו-v2 בחדש) ולוודא שמספר ה-Migrated … line ids≈ מספר השורות נושאות-heRef, ושהאזהרה על מעבר לא-נקי לא נורית.PRים נלווים
בדיקות
./gradlew build --no-daemon --no-configuration-cacheעבר במלואו (כולל Android וכל מודולי Kotlin); בדיקות ה-JVM שלgenerator-common,otzariasqliteו-sefariasqliteעברו; ו-162 בדיקות Python של סקריפטי ה-CI עברו (24 דולגו כצפוי). נוספו רגרסיות לקידומת+ניקוי ולסף 30%. טרם הורצה בנייה מלאה שלseforim.db; בדיקתdelta-real-diff-testנשארת שער חובה לפני release.