הבלוג של ארתיום
בלוג על לינוקס, תוכנה חופשית, מוזיקה, סלסה, ומה לא!
מאמרים בנושא CppCMS.
Wikipp רץ על CppCMS 1.x.x !
בשעה טובה, המרתי את Wikipp לגרסת אלפה של CppCMS 1.x.x והיא רצה סוף־סוף ב"ייצור".
עוד שלב חשוב לשחרור גרסת בטא של CppCMS 1.x.x - שבו תוכננו מחדש ושוכתבתו מחצית מהרכיבים פנימיים שלו.
עדכנו אותי אם אתם נתקלים בבעיות.
Boost חסרת תועלת למפתחי ספריות
Boost חסרת תועלת למפתחי הספריות, או ליתר דיוק מפתחי ספריות שמנסים לשמור על ABI יציב של הספריות שלהן. זהו שם הדיון שפתחתי ברשימת תפוצה של Boost שאני חושב שעוררה סערה קטנה בקרב המפתחים שלה. אני מאוד מקווה שזה יגרום לשינויים בתפיסה של Boost ובסופו של דבר יגרום ליצירת Boost-stable, או boost::abi.
רקע קצר: ספרית Boost היא אוסף ספריות C++ עשיר שנותן כלים מצוינים למפתחים. אפשר להשוואות אותה ל־JDK של Java שנותן לך כלים כמעט לכל דבר. בעיקר היא ממלא חורים רבים שחסרים בספרית C++ סטנדרטית: טבלאות hash, ביטויים רגולריים, מצביעים חכמים, תמיכה בחוטים (threads), ועוד ועוד ועוד.
למעשה החלקים הגדולים שלה כבר נמצאים בסטנדרט C++ הבא שישוחרר (בתקווה) בקרוב. למעשה, אם רוב הקומפיילרים היו תומכים ב־C++0x כבר לא הייתי זקוק למחצית הכלים שזמינים לי היום דרך Boost.
למעשה, Boost היא ספריה המנוהלת כמדיניות ע"י דחפים אבולוציוניים משפרת את התכנון שלה כל הזמן, אפיל רכיבים יסודיים ביותר כמו boost::shared_ptr
עוברים שיפורים משמעותיים. וכאן מתחילה בעיה:
- כל שלושה חודשים משוחררת גרסה חדשה של Boost.
- כל גרסה חדש אינה מבטיחה תאימות כלשהי הן של ABI ואפילו API.
בפועל זה גורם לכך ש:
- רוב החברות שעובדות עם Boost בד"כ תקועות עם גרסה מיושנות כי מפחדים לשדרג אותה
ישנים מקרים רבים של טעויות בהן שתי ספריות צד ג' בנויות עם גרסאות שונות של Boost פשוט קורסות ברגע שהן עבדות באותה יחידה (קובץ ריצה).
מה שבהחלט לא עוזר להטמעה של Boost לפרויקטים רבים, במיוחד ספריות, כי מטילות עליהן מגבלת תאימות גרסה קשות.
העליתי את זה (בפעם העשירית אולי) ברשימת התפוצה של Boost. אבל נראה לי הפעם זה יצר הד מסוים וגם נראה לי שקיר ה"אי־הבנה" התחיל להישבר, לפחות הרגשתי את זה ממספר מפתחי Boost מרכזיים.
כך או אחרת, בגלל הבעיות האלה וצרכים קיומיים של CppCMS:
- הסתרתי חלקי Boost שהייתי מוכרח להשתמש בהם תחת namespace חילופי.
- יצרתי ספריה חלופית Booster שבנויה עם API מאוד דומה ל־API של Boost אבל משתמשת ברכיבים אחרים: למשל, לתמיכה בביטויים רגולריים אני משתמש ב־PCRE ל־threadים אני משתמש ב־pthreads (גם בחלונות).
- חלקים קריטיים כמו
shared_ptr
פשוט לקחתי מ־Boost והתאמתי ליציבות בינארית. - חלקים שכתבתי כמו
booster::function
.
בגדול כל דבר שהייתי משתמש בו והייתי זקוק לו ב־API הכנסתי ל־Booster מ־Boost בצורה כזו או אחרת.
האמת? זאת הייתה החלט מאוד קשה ועצובה מבחינתי. כי ללא ספק Boost היא ספריה מצוינת, שאי אפשר בלעדיה ואני כל כך שונא "להמציא גלגל מחדש", מצד שני, Boost יכולה להפוך לסיוט בתנאים מסוימים ו־CppCMS זה בדיוק המקרה בו תלות ב־Boost היא סיוט מתמשך.
מי שמעוניין יכול לקחת Booster מ־svn כאן:
https://cppcms.svn.sourceforge.net/svnroot/cppcms/framework/branches/refactoring/booster
אבל תהיו מודעים לעובדה ש־Booster איננה Boost, והיא נבנתה לצורכי CppCMS בלבד.
שוחררה גרסת 0.0.5 של CppCMS (ענף יציב)
שוחררה גרסה חדשה של ענף יציב של CppCMS, שינויים:
תיקוני בעיות אבטחה:
- נכתב מעקף לבעיה של ספריית CgiCC שהיה יכול לגרום ל־DoS.
- תוקנה בעיה שהייתה עלולה לגרום להווצרות SID בעלי אנטרופיה נמוכה.
תיקוני באגים:
- תוקן זמן חיים של ערכים "חשופים" בניהול מצב (sessions)
- תוקן באג שמנע אפשרות עבודה ב־FastCGI/SCGI מעל TCP/IP
- תוקנו בעיות בניה עם גרסאות Boost לא סטנדרטיות.
- תוקנו בעיות ביצירת HTTP Status Headers לא נכונים במקרה של שגיאות.
- תוקנו בעיות בניה עם גרסאות gcc שונות ועם קומפיילר של אינטל.
שיפורים:
- שופרו זמני בעיות views בצורה משמעות.
ל־CppCMS יש קהילה פעילה
בחודש חודשיים אחרונים אני רואה פעילות ערה מסביב ל־CppCMS. רשימת התפוצה הפכה להיות פעילה, דיווחי באגים מגיעים ואפילו...
לפני ימים אחדים קיבלתי מספר דיווחי באגים ותרגום של הבלוג הזה לסינית, כך שאם מישהו רוצה בלוג שמיליארד סינים יוכלו לקרוא אותו בלי ליצור עומסים, זאת לא בעיה ;-).
האמת היא, אני שמח ש־CppCMS לאט־לאט צובר תאוצה והקהילה נבנית מסביבו.
נפלאות ה־Comet בשרתי האינטרנט המודרניים...
כפי שפרסמתי לאחרונה, אני עובד על תמיכה ב־Comet או HTTP Push ב־CppCMS. כאשר הכוונה לאפשרות שרת האינטרנט ליידע את הלקוח על אירוע חדש, למשל: "הגיעה מסר מידי חדש, או מחיר המניה השתנה" -- למעשה להעביר אירועים ללקוח בזמן אמת.
כיצד התהליך מתבצע? הלקוח פונה לשרת עם בקשת HTTP לקבל עדכונים; והשרת, במקום לענות באופן מידי ממתין ומחזיק את הקשר פתוח. כאשר מגיע האירוע החדש, כמו עדכון מחיר המניה או הודעה חדש מחבר, התשובה נשלחת והתליך חוזר.
לא מי יודע מה מסובך כמובן זה גם תלוי ביכולת השרת להחזיק קשר HTTP פתוח למשך הרבה זמן.
אבל, מה קורה אם הלקוח סוגר את הקשר לפני שהוא מקבל תשובה? בבקשות HTTP רגילות זה אירוע נדיר והיישום בצד השרת יכול בקלות "להתעלם" ממצב כזה. ביישומי Comet זה שונה: מספיק שמישהו נכנס לאתר שמחכה לדף שמבצע בקשה מסוג זה ויוצא ממנו, הקשר לקבלת עדכונים ייסגר.
אבל מה יישום Comet אמור לעשות? תחשבו שמספר הבקשות HTTP שנסגרות לפני דיווח על אירוע מסוים יכול להיות הרבה יותר גדול ממספר התגובות הרלוונטיות בפועל. אז יישום תקין צריך לזהות ניתוקים כאלה, ולמחוק אותם מ"רשימת התפוצה שלו".
אבל מה? יישום ה־Comet בד"כ לא מדבר ישירות עם הלקוח בעזרת HTTP אלא מדבר עם שרת web בעזרת פרוטוקול סטנדרטי כמו FastCGI או SCGI. לכן, תפקידו של השרת הוא לדווח ליישום על כך שהלקוח סגר את הקשר. למעשה פרוטוקול FastCGI מגדיר במפורש דרך להפסיק בקשה מסויימת ע"י סגירת ה־socket או שליחת בקשה מיוחדת "Abord Request", כנ"ל ניתן לבצע בעזרת scgi ע"י ניתוק ה־socket.
פשוט? כן. האם זה קורה בפועל? לא ממש.
אחרי שמימשתי מערכת ניתוק הקשר ובדקתי אותה על שרת http פנימי, החלטתי לבדוק את ההתנהגות של שרתי web אמתיים: Lighttpd, Nginx ו־Apache2. מה שגיליתי היה ממש לא נעים: למעט Nginx אף שרת לא מדווח על ניתוק הקשר לא מעל FastCGI ולא מעל SCGI.
לצורך דוגמה פשוטה, אני יצרתי חיבור ומיד סגרתי אותו, כך עשיתי עשר פעם.
- Nginx הוא היחיד דיווח על כך ליישום FastCGI באופן מידי ואפשר לי לטפל בלקוח ש"נעלם"
- Apache דיווח רק אחרי timeout ארוך של כדקה הן ב־FastCGI והן ב־SCGI.
- lighttpd בכלל שכח מזה והחזיק קשרים פתוחים כל הזמן -- יותר מזה בירידה, הוא התלונן על כך שהיישום שלי "נעלם" ולא ענה לבקשת השרת (שאין לו כבר למי להעביר אותה).
בקיצור... זה היה מאוד מאכזב. אני הייתי מוכן לקבל את זה מ־Apache שידוע כשרת שלא נועד לטפל בהרבה קשרים פתוחים, אבל Lighty? פתחתי על זה באג.
מזל שמימשתי שרת HTTP פנימי בעצמי.