נתון מערך בגודל NxN של פיקסלים כאשר כל הפיקסלים שחורים חוץ מאחוז מסויים מהם שאינו שחור ומפוזר באופן אקראי,
בהינתן קואורדינטה (x,y) מסויימת בתמונה, מצא במהירות את כל הנקודות שנמצאות בתוך חלון בגודל K על K (כאשר K קבוע בבעיה) שמרכזו (x,y), משהו כזה:
פעולת המציאה עצמה צריכה להיות מהירה מאוד, אבל מותר לעבד מראש את התמונה פעם אחת (בזמן סביר).
אז הנה הפתרון שלי:
נחלק את התמונה למשבצות בגודל KxK, ונשמור רשימה של כל הנקודות בכל משבצת.
כאשר מבקשים מאיתנו לתת את רשימת הנקודות בחלון מסויים, נסתכל בארבעת החלונות שהחלון הזה חותך ונסנן את כל הנקודות בארבעת החלונות שלא נמצאות בתוך החלון המבוקש.
זה הכל בעצם.
הביצועים של הפתרון הזה מעולים, כדי להכין את הגריד (Grid) נעבור על כל הפיקסלים בתמונה, ולכל נקודה נמצא בזמן קבוע את המשבצת שאליה היא שייכת.
כשממש מחפשים את הנקודות בחלון מסויים, נבדוק במקרה הגרוע 2K*2K פיקסלים (אם כל הנקודות לבנות) אבל במקרה הרגיל נבדוק הרבה פחות (ואם החלון לא מכיל נקודות כלל נדע את זה מהר מאוד).
זה הקוד של העיבוד המקדים:
privatestaticint[][][] buildgrid(byte[][] image, int width, int height, int gridSize) { int grid[][][] = newint[width / gridSize][height / gridSize][]; // count the number of points in each grid cell int numpoints[][] = newint[width / gridSize][height / gridSize]; for(int x=0;x<width;x++) { for(int y=0;y<height;y++) { if(image[x][y] > Byte.MIN_VALUE) {
numpoints[x/gridSize][y/gridSize]++; } } }
for(int x=0;x<width;x++) { for(int y=0;y<height;y++) { int c = image[x][y]; if(c > Byte.MIN_VALUE) { int gy = y/gridSize; int gx = x/gridSize; int list[] = grid[gx][gy]; if(list == null) { int np = numpoints[gx][gy];
list = newint[np * 2];
grid[gx][gy] = list;
numpoints[gx][gy] = 0; }
הקוד הבא סופר את המספר הנקודות בתוך החלון שמרכזו (x,y)’ שימו לב שהלולאות עוברות על ארבעה ריבועים בגריד בלבד:
// window boundaries: int rx1 = x – grid_size/2; int ry1 = y – grid_size/2; int rx2 = rx1 + grid_size; int ry2 = ry1 + grid_size;
// top left grid cell (out of 2×2 group to be checked) int gx = rx1 / grid_size; int gy = ry1 / grid_size;
for(int grid_x=gx;grid_x<gx+2 && grid_x >= 0 && grid_x < gwidth;grid_x++) { for(int grid_y=gy;grid_y<gy+2 && grid_y >= 0 && grid_y < gheight;grid_y++) { int list[] = grid[grid_x][grid_y]; if(list == null) continue; for(int i=0;i<list.length/2;i++) { int jj = i*2; int dx = list[jj]; int dy = list[jj+1]; if(dx >= rx1 && dx < rx2 && dy >= ry1 && dy < ry2) {
c++; } } } }
יתכן שאפשר לשפר את הביצועים אם נחלק את הגריד לריבועים יותר קטנים ונכלול ריבועים שלמים שנופלים בתוך החלון בלי לבדוק כל נקודה באופן פרטני, אבל לא ניסיתי.
הביצועים של הפתרון הזה די מטורפים. על Q6600 במהירות 2.4GHZ, עם תמונה בגודל 500X500 פיקסלים וחלון של 20X20, בדיקה של כמה זמן לוקח לספור את הפיקסלים בכל 250,000 החלונות האפשריים לקחה כ160 מילישניות, מה שנותן מהירות בדיקה של מעל 1500 חלונות במילישניה (או יותר ממליון וחצי חלונות בשניה), בלי תלות בגודל התמונה שנבדקת (על תמונה של 1000X1000 המהירות היתה דומה).
האפלט הבאה מדגימה את האלגוריתם. אפשר להוריד אותה מפה. הקוד כלול בתוך הJAR (אפשר לפתוח את הJAR עם תוכנה לפתיחת קבצי ZIP).
בנוסף, האפלט יכולה לרוץ כתוכנית רגילה : java -jar fast_window.jar
אפשר ללחוץ בתוך האפלט כדי לסמן את הנקודות בחלון.
לפני כמה שנים טובות עבדתי בסטארטאפ קטן בשם Content Objects שנסגר זה מכבר.
בתקופתי שם פיתחתי ספרית ג’אווה בשם JNotify שמאפשרת קבלת ארועים על שינויים במערכת הקבצים בלינוקס ובחלונות (ואולי עוד בהמשך).
דאגתי שהקוד ישוחרר ברשיון קוד פתוח כפרוייקט סורספורג’.
החברה נסגרה (אחרי שעזבתי), אבל הקוד נשאר. לא ממש תחזקתי אותו, אבל נראה שאנשים השתמשו בו בכל זאת – למרות שהיו כמה בעיות די חמורות בגרסאת החלונות.
כדי לתת מה שהספריה נותנת, חייבים להשתמש בקריאה לפונקציות של מערכת ההפעלה.
בלינוקס העניין היה פשוט יחסית: קטע הקוד המקומי (native code) הוא מינימלי ביותר ומסתמך על inotfiy. הAPI שלו מאוד פשוט אבל הוא לא תומך בהאזנה ריקורסיבית ולכן רוב הקוד כתוב בג’אווה ונועד להוסיף יכולת לקבלת ארועים על ספריות באופן ריקורסיבי (צפיה בתת ספריה על כל בניה).
בחלונות העניין הפוך, קריאת המערכת ReadDirectoryChangesW תומכת בהאזנה ריקוסיבית, אבל השימוש בה מורכב ברמות שלא יאמנו והתיעוד של מייקרוסופט מחורבן ביחס ישר למורכבות הAPI. ולכן על חלונות רוב הקוד כתוב בC++ (כי אין דרך פשוטה להתממשק אל הAPI המקומי מג’אווה) אבל קוד הג’אווה הספציפי לחלונות פשוט מאוד.
מכיוון שהרבה יותר קל לכתוב ולדבג קוד ג’אווה מאשר קוד C++, המימוש ללינוקס היה הרבה יותר יציב מזה של חלונות – שנטה להתרסק או להתקע לעיתים נדירות בכל מני סיטואציות שלא הצלחתי לשחזר.
לפני כמספר שבועות פנה אלי משתמש של הספריה, והציע שאני אפתור בתשלום את הבאגים בגרסאת החלונות.
לאחר משא ומתן קצר הסכמנו על $100, וניסיתי את מזלי.
זה היה די קשה, אבל לבסוף הצלחתי לתקן את הבאגים החמקמקים, ובנוסף לשפר את הביצועים של הספריה כך שלא תפספס אירועים גם על מחשבים חלשים.
אחרי שכמות השעות ההשקעתי בעניין עברה את מה שנראה לי מוצדק בעבור $100 הסכמנו גם להגדיל את הסכום ל$250 והיום שחררתי את הגרסא המתוקנת
$250 זה לא סכום שבאמת מכסה את כמות השעות שהשקעתי בתיקון הבאגים (אם הייתי לוקח סכום סביר לשעה), אבל זה בכל זאת פרוייקט קוד פתוח ואני מרוצה שתיקנתי את הבאגים האלו.
נודע לי מאותו משתמש שמישהו ביצע fork לספריה והוסיף לה תמיכה בMac.
פניתי אליו ונראה שהוא יצטרף לפרוייקט וישלב את התוספת שלו בקוד (שנכתב כך שיהיה קל מאוד להוסיף תמיכה במערכות הפעלה חדשות), ואולי גם יעזור עם באגים אחרים.
עם השנים נוספו לג’אווה כלים סטנדרטיים שמאפשרים חיבור למכונה וירטואלית חיה, ובחינה של מה שקורה שם ככלי למציאת בעיות בזמן הריצה של תוכניות.
jps : מראה תהליכי ג’אווה
jstack : מציג את רשימת הת’רדים בתהליך ג’אווה, ומה כל אחד מהם עושה.
jmap: מאפשר שמירה לקובץ של תמונת הזכרון (heap dump) של תהליך ג’אווה. אפשר לבחון את הקובץ עם jhat או עם VisualVM.
jhat : מאפשר ניתוח קבצי heap dump שנוצרו בעזרת jmap.
jconsole : ממשק פשוט שמאפשר בחינה של שימוש הזכרון, שימוש בזמן מעבד ועוד.
visualvm: כלי חזק יותר מjconsole, שהחל מעדכון 18 של JDK 1.6.0 מגיע עם הJDK. ויז’ואל VM מאפשר גם ניתוח ביצועים פשוט (cpu and memory profiling).
כל הכלים האלו תומכים גם בגישה למכונה מרוחקת בצורה זו או אחרת, הבעיה היא שכמעט בלתי אפשרי להתחבר איתם למכונה שמוגנת בפיירוואל כי הם עובדים עם פורטים אקראיים.
אם עם כלי שורת הפקודה עוד אפשר להסתדר על שרת מרוחק (קל יותר להריץ jps ישירות על השרת מאשר לנסות לעשות את זה מרחוק), עם הכלים הגראפיים הסיפור כבר אחר.
VisualVM
אז איך בכל זאת אפשר להתחבר לתהליך ג’אווה מרוחק עם VisualVM?
התהליך קצת מורכב, ולכן אני אתעד אותו כאן:
על המחשב המרוחק:
1. צרו קובץ permissions.txt שיכיל את זה:
grant {
permission java.security.AllPermission;
};
2. הריצו את jstatd (שמאפשר לתהליכים מרוחקים לקבל רשימה של מכונות ג’אווה שרצות על המכונה ולהתחבר אליהן) :
jstatd -J-Djava.security.policy=permissions.txt
3. הריצו את התוכנית שלהם עם הפרמטר הבא:
java -Dcom.sun.management.jmxremote MainClass
על המחשב המקומי:
1. צרו תעלות SSH לשרת כך:
ssh -D9696 -L1101:localhost:1099 your_server
שימו לב שיש פה שתי ‘תעלות’:
תעלת TCP מ1101 אל 1099 בשרת המרוחק. זו תעלה שמאפשרת להתחבר אל הjstatd ישירות.
עבר הרבה זמן מאז שהיה פה פוסט רציני, כל פעם שהיה לי על מה לכתוב זה איך שהוא התמסמס ותוייק בתיקיית האחר כך.
אז זה יהיה פוסט מוזר, מוזר מאוד אפילו – שיהיה בעצם ערמת פוסטים מרוכזים.
אולי במהלך הכתיבה של תת פוסט כזה אני אגלה שאני מעדיף שהוא יהיה בעצם פוסט שלם, אבל נראה.
שרת חדש
הגיעה התקופה הזו, שבה אני פחות מרוצה מההוסיטנג שלי ועברתי להוסיטנג חדש.
למעשה הייתי מרוצה מספיק מeSecureData (אליהם עברתי מHCOOP לפני פחות משנה וחצי).
מהירות התקשורת היתה קצת מאכזבת אבל לא היו יותר מדי תקלות.
אז למה עברתי?
במסגרת העבודה שלי בface.com (כן, אני עובד בface.com, לא חושב שיצא לי להזכיר את זה פה עד עכשיו) אני עובד מול חברת אכסון בשם CentralHost בסן דייגו, ומחזיק אצלם מספר לא מבוטל של שרתים. בשנה וחצי בשנה חצי שאני עובד שם, הייתי מאוד מרוצה מהם ומרמת התמיכה שלהם – אם כי המחיר שלהם הוא גבוה משמעותית מזה של eSecureData, לפחות למכונות החזקות שאני מחזיק שם במסגרת העבודה.
בכל אופן, יש לי יחסים מצויינים עם בעל החברה, וכששאלתי אם יש לו הצעה אלטרנטיבית שתאפשר לי להעביר את השרת שלי אליו הוא הסכים לתת לי מחשב באותו מחיר שאני מקבל בeSecureData – שזה $79 לחודש, עם יותר זכרון (4 ג’יגה במקום 2 ג’יגה), ושני הרדיסקים של 500 בתצורת רייד 1 (ראי, אם הרדיסק אחד מת לא קורה כלום ופשוט מחליפים אותו) לעומת הרדיסק אחד בלבד בשרת הישן.
העברתי בעזרתו את השרת למכונה החדשה, ולמעט שינויי הגדרות קטנים בשרת הDNS שאני מריץ, ובהגדרות הDNS ברשת הדומיינים שלי הכל פשוט עובד.
אני בטוח שיהיו עוד חבלי לידה, אבל אם אתם קוראים את זה, אתם עובדים מול השרת החדש.
אז כמו תמיד, יש לי מקום לאורחים. מי שחושב לעבור שרת למשהו יותר רציני מאיכסון משותף בגודדי שיצור קשר. (רק לאנשים שמרגישים בנוח עם SSH).
BoneCP
השתמשתי בProxool בתור Connection pool לבסיס הנתונים במשך די הרבה זמן, ועם הזמן גיליתי בעיות – שאומנם די נדירות אבל מספיק חמורות כדי שאני אחפש פתרון.
חשבתי לפתור אותן בעצמי, וגיליתי שהוא לא מתקמפל על JDK מודרני. שלחתי מייל לרשימת התפוצה שלו לגבי העניין, וחודשים עברו בלי שום תגובה ובלי הודעות נוספות.
היה ריח של פרוייקט מת באוויר, וכשנתקלתי בבעיה נוספת (100% CPU בקוד של פרוקסול לעיתים נדירות), החלטתי לחפש Connection pool אחד.
בסוף הגעתי לBoneCP שאומנם מוגדר כבטא, אבל עובד היטב – וחשוב יותר – המפתח שלו עונה לאימיילים ומתקן באגים.
טיפוסי אישיות
מי שלמד פסיכולוגיה (לא אני) מכיר את העניין הזה לעומק כנראה, אבל אני מניח שרוב הקוראים פה לא למדו פסיכולוגיה אני אכנס לעניין:
במהלך שיטוטי באינטרנט בחיפוש אחרי ספרייה לDecoding של תמונות בC או C++ (יש מילה בעברית לDecoding? פענוח? פרישה?) נתקלתי בCxImage, וראיתי בדף האודות של המפתח שהוא טוען שהאישיות שלו היא מסוג INTJ.
אני די בטוח שנתקלתי בסוג הקטלוג הזה למחלקות אישיות בעבר, אבל הפעם הסתקרנתי, אם הוא INTJ אז מה אני? וכמה הדבר הזה בכלל עובד?
התחלתי לחקור, מסתבר שמדובר במבחן פסיכומטרי שמבוסס על העבודה של קארל יאנג מ1920 ופותח על ידי קתרין קוק בריגס וביתה איזבל בריגס מיירס, והמבחן קרוי על שמן: Myers-Briggs Type Indicator או MTBI.
בגדול, הרעיון הוא שהאישיות של בני אדם נקבעת על ידי ארבעה תכונות, כאשר לכל תכונה יש שני צדדים (מוחצן – מופנם, חושב – מרגיש) וכו’, ואצל כל אחד תכונה אחת מכל זוג היא יותר דומיננטית מהשניה.
הזוגות הם:
התנהגות – מוחצן או מפונם : האם רוב המחשבה של האדם מופנית החוצה או פנימה
תפיסה – חש או אינטואיטיבי : איך האדם קולט מידע חדש, האם הוא סומך יותר על תחושות פנימיות או על מידע קונקרטי
החלטה – חושב או מרגיש : איך האדם מבצע החלטות רציונליות בניתוח של המידע שהוא קיבל באמצעי התפיסה, האם הוא מעדיף חשיבה וניתוח לוגי או החלטה לפי הרגשה והזדהות עם המצב.
סיגנון חיים – שיפוטי או תפיסתי : האם האדם מעדיף להשתמש בבהחלטה (חושב/מרגיש) או בתפיסה (חש/אינטואיטיבי) כשהוא מתייחס אל העולם החיצוני.
קצת מבלבל, ואולי התרגום שלי לא מאוד מדוייק (יש הרבה מאוד חומר מדוייק על זה באינטרנט).
סך הכל יש ארבע ‘ביטים’ כשלכל ביט יש שתי אפשרויות, מה שיוצר 16 קומבינציות.
מצאתי מבחן עם כ-70 שאלות כן/לא שמוצא את הטיפוס שלכם, וקיבלתי שגם אני INTJ.
קראתי קצת על INTJ, ונראה שלפחות לגבי – המבחן יצא מאוד מדוייק.
בעיית החלוקה
שוב ושוב אני נתקל בבעיה הבאה:
בהנתן קבוצת מספרים, איך מחלקים אותה לשתי קבוצות כך שסכום המספרים בכל קבוצה יהיה קרוב ככל האפשר לסכום המספרים בקבוצה השניה.
במילים אחרות, שאף קבוצה לא תהיה ‘כבדה’ הרבה יותר מהשניה בצורה שניתנת לתיקון על ידי סידור מחדש של האיברים בקבוצות.
הרחבה טבעית של השאלה הזו, היא איך מחלקים את הקבוצה לk קבוצות, לאו דווקא רק לשתיים.
הנה כמה דוגמאות למצבים שבהם אלגוריתם כזה יהיה שימושי:
דמיינו משחק מרובה משתתפים שעובד בסיבובים. בכל סיבוב יש שתי קבוצות שנלחמות אחת בשניה. חלוקה אקראית של השחקנים לשתי קבוצות תגרום למצב שבו כל השחקנים החזקים נופלים בקבוצה אחת ואז המשחק לא יהיה מהנה במיוחד לאף אחת מהקבוצות.
חלוקה אידיאלית תהיה כזו שההפרש בין סכומי היכולת בכל קבוצה יהיה נמוך (קבוצות מאוזנות). נניח שיש לנו מדד ליכולת של שחקן (יחס נצחונות/הפסדים ב20 המשחקים האחרונים, או דרגה או כל דבר אחר) נוכל להשתמש באלגוריתם חלוקה כזה כדי למצוא חלוקה טובה של הקבוצות.
דוגמא נוספת: נניח שיש לכם ערמת עבודות, וכמה מחשבים שיכולים לבצע את העבודות. איך תחלקו את העבודות בין המחשבים כך שעבודות יסתיימו בהקדם? אם אחד המחשבים יקבל את כל העבודות הכבדות אז הוא יסיים הרבה אחרי כולם, אז שוב אנחנו מחפשים חלוקה מאוזנת (הפעם לk מחשבים).
אוקיי, עכשיו שמצאנו למה פתרון לבעיה הזה יהיה שימושי, תחשבו על הבעיה ואם יש לכם פתרון נדבר עליו בתגובות.
אני אדבר על הפתרון שלי בפוסט הבא.
לפני קצת יותר משנה גוגל שחררו ברשיון קוד פתוח פרוייקט בשם Protocol Buffers, ובקיצור protobuf.
protobuf מגדיר שפה להגדרת מבני נתונים (IDL), ויודע לייצר קוד יעיל שקורא וכותב את אותם מבני נתונים בC++, JAVA או פייתון.
יש תמיכה חיצונית לפורמט בשפות נוספות, C#, D, רובי PHP* ועוד.
הדוגמאות שאני אתן יהיו בג’אווה, אבל השתמשתי בו גם עם C++ והוא עובד היטב גם שם.
כל מפתח מגיע מתי שהוא לשלב שבו תוכנית שהוא כותב צריכה להעביר נתונים לתוכנית אחרת (או למופע אחר של עצמה) דרך הרשת, או לשמור נתונים לקובץ כדי לקרוא אותם אחר כך.
מקובל לקודד את הנתונים בתוך הודעות, כשיש הרבה מאוד דרכים לכתוב את ההודעות, ובדרך כלל מדובר בקוד די סיזיפי שחוזר על עצמו וכתיבתו היא די משעממת (בפעם העשירית שעושים משהו כזה).
נניח שאנחנו רוצים להעביר אובייקט שמייצג אימייל על גבי הרשת (ונתעלם רגע מהפרוטוקולים המקובלים להעברת אימיילים).
לאובייקט אימייל שלנו יש שדה של שולח, אחד או יותר שדות של מקבלים, נושא, טקסט, ואפס או יותר קבצים נלווים ואפילו עדיפות.
אפשר לייצג אותו במבנה הלוגי הזה:
package messages;
message Email {
enum Priority {
LOW = 1;
NORMAL = 2;
HIGH = 3; }
message Attachment {
optional string data = 1;
required string name = 2; } }
מה שיש לנו פה זה הגדרת הודעה תקינה בשפת הIDL של protobuf.
השפה תומכת בהגדרת חבילה (שמתורגמת לpackage בג’אווה ולnamespace בC++), וכן בהגדרות מקוננות של הודעות.
המספרים אחרי כל שורה נקראים טאגים ומשמשים לזיהוי של השדות בפרוטוקול הבינארי, ולכן אחרי שהם נקבעים אי אפשר לשנות אותם.
אפשר לראות שהשפה תומכת בהגדרה של enum, וכן ברשימות של אובייקטים (שיכולים בעצמם להכיל אובייקטים וכן הלאה).
חוץ מטיפוסים שאתם מגדירים, השפה תומכת גם בטיפוסים פנימיים למשל מחרוזת, משתנה בוליאני, מספר ברוחב קבוע (למשל ארבעה בתים), מספר ברוחב משתנה ועוד.
המספרים ברוחב משתנה מקודדים בצורה דומה קצת לקידוד של UTF8, אבל בצורה קצת יותר פשוטה:
הביט השמאלי (MSB) בכל בייט מוגדר כך: 1 אם המספר המועבר כולל בייטים נוספים, או 0 אם זה סוף המספר.
7 הביטים האחרים בכל בייט משמשים להעברת 7 ביטים של המספר עצמו. בצורה כזו, מספרים קטנים מ128 יתפסו בייט אחד בלבד, מספרים קטנים מ65000 בקירוב יתפסו שני בתים וכן הלאה. אם התוכנית שלכם מעבירה מספרים קטנים שיכולים להיות גדולים לעיתים נדירות – הקידוד הזה הוא אידיאלי כי בדרך כלל המספרים לא יתפסו הרבה מקום, בניגוד לקידוד ברוחב קבוע שבו כל מספר תופס למשל ארבעה בתים.
חלק מהטיפוסים הנתמכים בשפה הם ברוחב קבוע, למשל מספרים בנקודה צפה (Floating point) ושלמים שמוגדרים כFIXED, למשל FIXED64 יהיה תמיד 64 ביטים או 8 בתים.
עוד על השפה אפשר לקרוא פה.
את הקובץ שמכיל את הגדרת ההודעות “מקמפלים” עם protoc, שמייצר ממנו קוד בג’אווה C++ או פייתון:
$ protoc messages.proto –java_out src/
הנה דוגמא לקוד ג’אווה שמייצר הודעה, כותב אותה לקובץ, קורא אותה ומדפיס אותה בפורמט טקסטואלי:
class Test { publicstaticvoid main (String args[])throwsFileNotFoundException, IOException {
Builder b = Email.newBuilder();
b.addTo(“test@abc.com”);
b.addTo(“test@loogle.com”);
b.setFrom(“someone@there.com”);
Attachment aa = Attachment.newBuilder().setName(“viruts.exe”).build();
b.addAttch(aa);
b.setSubject(“A present for you”);
b.setMessage(“Please open the attached Virus”);
Email email = b.build(); System.out.println(email.toString()); FileOutputStream out = newFileOutputStream(“email.dat”);
email.writeTo(out);
out.close();
$ javac -cp lib/protobuf-java-2.2.0.jar src/Test.java src/test/Messages.java
$ java -cp lib/protobuf-java-2.2.0.jar:src Test
from: “someone@there.com”
to: “test@abc.com”
to: “test@loogle.com”
subject: “A present for you”
attch {
name: “viruts.exe” }
message: “Please open the attached Virus”
אפשר לראות שבמפתיע הפלט הטקסטואלי הוא כמעט קובץ Swush תקני, אני נשבע שלא הסתכלתי עליו כשהגדרתי את Swush
זו דוגמא לשימוש בprotobuf בג’אווה, השימוש בC++ בשפות אחרות פשוט בצורה דומה.
כל העניין מאוד קל לשימוש, ואני ממליץ מאוד לכל מי שצריך לכתוב אובייקטים לקובץ או לרשת לבדוק את protobu.
אגב, הקוד המחולל נראה טוב מאוד, כמעט כאילו כתבתם אותו בעצמכם.
* PHP : הספריה לתמיכה בPHP היא pb4php, והיא לא מאוד מוצלחת. למרות שיתכן שבקרוב הפרוייקט יקבל PATCH משמעותי שהופך את הספריה ליותר שמישה (לפחות לצרכים שלי).
אחד המשחקים המצופים של השנה – Dragon age: Origins - יצא לפני אתמול, ואחרי שראיתי את הציונים והביקורות שהוא קיבל החלטתי לקנות אותו.
חיש מהר קניתי אותו בSteam, חנות המשחקים שלValve.
בזמן שקניתי אותו היה נראה כאילו אני מבצע הזמנה לפני שהמשחק יצא (Pre order), אבל מה שקורה בדרך כלל זה שאפשר להוריד את המשחק מראש, וברגע שהוא משתחרר (מה שהיה אמור להיות אתמול) קבצי המשחק המוצפנים עוברים תהליך של פענוח ואז אפשר לשחק.
אבל מה? מסתבר שבארצנו הקטנטונת – וגם באירופה, המשחק ישוחרר רק ביום שישי או שבת.
סתם כדי להתעצבן, בדקתי באתר הטורנטים הקרוב לביתי, ואכן – המשחק כבר שם.
שלחתי אימייל לתמיכה של Valve, בו מחיתי על כך שהם מסרו מידע שגוי שגרם לי ולאחרים לקנות את המשחק ולהצטער.
אז המשחק כבר אצלי, מוצפן – ושילמתי עליו, אבל מסיבות עלומות ומציקות אני לא מורשה לשחק בו למרות ששחקנים אחרים בעולם כן.
מעצבן מספיק כדי לפעול.
משתמשים בפורום של Steam כתבו שהם הצליחו לשחק אחרי שהתחברו לSteam תוך שימוש בVPN שמחובר לארצות הברית.
חיפשתי קצת, ולא מצאתי משהו שלא ביקש ממני כרטיס אשראי בשביל לנסות, אז חשבתי לעצמי:
השרת שמריץ את הבלוג נמצא בקנדה, רוב הסיכויים שהמשחק שוחרר בקנדה באותו תאריך כמו בארצות הברית.
החלטתי להרים שרת VPN על השרת בעזרת ההוראות פה.
ההוראות פשוטות למדי, אבל במקום לאתחל את השרת כמו שהם הציעו אחרי ההגדרות הפעלתי מחדש את pptpd:
/etc/init.d/pptpd restart
כדי להפעיל את קידום הפקטות בקרנל בלי לאתחל, הרצתי את:
echo 1 > /proc/sys/net/ipv4/ip_forward
פתחתי חור TCP בפיירוואל בשרת בפורט 1723, שהוא הפורט הסטנדרטי של העניין הזה, וכמובן בחרתי סיסמא חזקה עם gpw שמייצר סיסמאות שאפשר להגות (Generate pronounceable passwords), ניסיתי להתחבר דרך מכונת המשחקים שלי שמריצה חלונות 7 (מערכת מומלצת), והעסק התחבר בלי בעיה.
בדקתי את כתובת הIP שלי בwhatismyip.com ולשמחתי ראיתי שהיא הכתובת של השרת.
הפעלתי מחדש את Steam, נכנסתי מקנדה – והפלא ופלא, בתור קנדי הצלחתי להפעיל את המשחק.
נראה שאני צריך להפעיל את Stream עם הIP הקנדי שלי כדי שהוא יסכים להעלות את המשחק (גם אחרי שהקבצים פוענחו), אבל זה רק לכמה הימים הקרובים.
קצת נמאס לי לפתוח אתר חדש לכל פרוייקט קטן שאני רוצה לחלוק, אז החלטתי לאכסן את כל הפרוייקטים הקטנים העתידיים שלי באתר אחד שמריץ את trac.
האתר נקרא כמובן:
כרגע יש בו שני פרוייקטים:
1. Zync : משלב בין rsync וzfs, כדי לגבות שרתים מרוחקים.
2. MySQL Monk : מנטר את מצב הרפליקציה של שרתי MySQL ושולח אימייל אם הם מתחילים לזייף (הסלייב נשרך יותר מדי מאחורי המאסטר, או שאחד השרתים למטה).
שני הפרוייקטים הנ”ל מתבססים על Swush כשפת הקונפיגורציה שלהם.
הAPI של Swush כבר מספיק עשיר ויציב, וממש כיף לי להשתמש בו.
errors: No known data errors
omry@iron:~$ zfs list
NAME USED AVAIL REFER MOUNTPOINT
rpool 7.46G 31.7G 81K /rpool
storage 1.54T 672G 1.53T /storage
storage/backup 9.35G 672G 9.35G /storage/backup
…
מה מעניין פה?
מערכת הקבצים של מחיצת השורש – הrpool, נמצאת על שני דיסקים (ליתר דיוק – על מחיצות של שני דיסקים), בתצורת ראי, מה שאומר שאם אחד מהם קורס, המערכת ממשיכה לעבוד. כמובן שבמצב כזה כדי להחליף את הדיסק התקול כמה שיותר מהר.
שאר המקום בשני הדיסקים הראשונים, וכל המקום בשני הדיסקים השניים הוקצה למערכת הקבצים storage, שמשמשת לאכסון, לגיבוי של מחשבים אחרים וכנראה גם כמערכת קבצים מרכזית של ספריית הבית שלי.
בהתחלה שקלתי ללכת על תצורת RAIDZ כדי לנצל כמה שיותר מקום.
הבעיה הגדולה מבחינתי עם RAIDZ היא שהדיסקים שמרכיבים את הpool צריכים להיות באותו גודל (אחרת מפסידים את המקום העודף בדיסקים הגדולים יותר).
מהסיבה הזו הלכתי על RAID10, עם שני זוגות של מירורים בנפח כולל של כ2.5 טרה בייט.
ביום שיהיה לי שם צפוף, אני אוכל לזרוק עוד צמד דיסקים פנימה ולקבל מקום נוסף מיד (בלי להזיז נתונים, להגדיל מערכות קבצים או דברים מעצבנים אחרים).
שיתוף קבצים בין מחשבים
יש לי עוד שני מחשבים, אחד מריץ רק לינוקס, ואחד מריץ לינוקס וחלונות (במכונה וירטואלית בשביל iTunes ימח שמו), ובדואל בוט בשביל משחקים.
כדי לשתף קבצים עם הלינוקסים, הגדרתי שיתוף בNFS.
את NFS פיתחו בסאן, והמימוש שלהם הוא המימוש הטוב ביותר של NFS, הבעיה היא שהמימוש של לינוקס הוא לא ממש לפי התקן, לפחות אם נאמין לשמועה הרווחת.
בזמן העברת קבצים מלינוקס לאופן-סולריס על גבי NFS נתקלתי בבעיות, ההעתקה הופסקה מעצמה בהעתקת קבצים גדולים עם שגיאה קלט/פלט סטנדרטית : די מטריד.
אחרי שווידאתי שהבעיה היא בNFS (העתקתי את הקובץ הגדול באמצעות SCP ווידאתי שהוא תקין עם md5sum) התחלתי לשחק בפרמטרים של NFS בצד הלינוקס, באיזה פרוטוקול הוא מתחבר (NFS4? NFS3? אולי אפילו NFS2 השם ישמור?), באיזה תעבורה? UDP או TCP.
בסוף גיליתי את התצורה שעובדת וגם נותנת ביצועים טובים:
NFS3 עם TCP, ועם חוצצי קבלה ושליחה בגודל 32K (בשביל הביצועים, לא היה להם השפעה על השגיאה).
השורה הרלוונטית /etc/fstab בלינוקס נראית ככה:
כדי לשתף עם חלונות השתמשתי בסמבה של גנו – אותו סמבה בדיוק שיש בלינוקס.
לאופן סולאיס של שני פתרונות לשיתוף קבצים עם חלונות: שרת CIFS שמובנה בתוך הקרנל, שמשום מה לא עבד לי טוב במיוחד, וחבילת samba סטנדרטית למדי, שעבדה הרבה יותר טוב.
גיבוייים של מכונות לינוקס
אין ספק שאיירון היא המכונה הכי עמידה שיש לי בכל מה שקשור לאכסון קבצים ועמידות לקריסת דיסקים (דיסקים קורסים, זו עובדת חיים).
מכיוון שכך, זה רק טבעי שאני ארצה לגבות של מכונות הלינוקס שלי אל איירון.
בעבר תיארתי את אסטרגיית הגיבוי שלי של מכונות לינוקס.
בגדול הרעיון הוא לבצע rsync של הקבצים הרלוונטיים, ולשלב את זה עם רוטציה של ספריות סנאפשוט בזמנים שונים. כדי למנוע בזבוז מיותר של מקום – משתמשים בhard links כך שקובץ שלא שונה מהגיבוי האחרון תופס מקום פעם אחת בלבד.
זה נחמד, אבל די מסורבל : צריך להעתיק את העץ מחדש כל פעם, ולמחוק עצים מיותרים, ובנוסף השיטה של החיסכון במקום לא מושלמת – כי קובץ ששונה רק בביט אחד יתפוס את כל המקום של הקובץ מחדש.
עם הסנאפשוטים של ZFS אפשר לעשות משהו הרבה יותר פשוט ואלגנטי, שגם יותר חסכוני במקום והרבה יותר מהיר.
הרעיון הוא פשוט לסנכרן את הספריה או הספריות הרלוונטיות מהשרת (או השרתים) אל ספריית היעד, ולקחת סנטפשוט של ZFS. כדי למנוע התפוצצות סנטפשוטים, אפשר פשוט למחוק סנאפשוטים ישנים.
כתבתי תוכנה פשוטה בשם zync שמממשת את הרעיון הזה.
כתובה בג’אווה, וקובץ ההגדרות שלה כתוב בswush, אז הוא קריא ונחמד.
הנה קובץ הגדרות לדוגמא:
כזכור לקוראים הוותיקים, אני משדרג די סדרתי.
לפני כשלוש שנים שדרגתי את מחשבי למפלצת זוללת ביטים שהתיישנה קשות מאז, פנטיום D, עם 2 ג’יגה זכרון, לוח אם פיצוצי של אסוס וכל זה.
הזמן עבר, ובשדרוג סיבובי טיפוסי שדרגתי את המחשב לפנטיום קור-דואו, והעברתי את הפנטיום D לסלון, וראיתי כי טוב.
עוד זמן עבר, והפנטיום D התחיל לגמגם בטיפול בוידאו ברזולוציה של 1080p, בהתחלה נסיתי להוציא ממנו עוד קצת חיים בשימוש בקודקים מתוחכמים, אבל בשלב מסויים ירדתי מהעניין וקניתי פנטיום i7 לחדר, ואת הקור-דואו שמתי בסלון. הפעם כבר לא היה לי שימוש למפלצת שזללה ביטים בימיה הטובים, ושמתי את לוח האם, המעבד והזכרון שעדיין עבד בקופסא, בתקווה למצוא לחומרה שימוש מתישהו.
פסט-פורוורד להיום.
יצא לי להתעסק עם אופן סולאריס, ופשוט התאהבתי בZFS.
ZFS היא ה-מערכת קבצים הכי טובה שראיתי, יש לה פיצ’רים שאין לאף מערכת קבצים אחרת.
מה למשל, שואל הקורא הסקרן?
טוב, אז ככה:
checksum של הנתונים עצמם, כולל ריפוי אוטומטי במקרה של נזק לנתונים (!) במקום נזק שקט כמו במערכת קבצים אחרות.
סנאפ-שוטים של מערכת הקבצים, שלא תופסים מקום ולוקחים זמן קצר במיוחד.
איך לא תופסים מקום? די פשוט, ברגע שמבצעים את הסנאפ-שוט (מעתה – צילום), מערכת הקבצים מסמנת שיש עליה סנאפ שוט וממתי הוא.
זה הכל.
ברגע שבלוק חדש נכתב, הוא לא נכתב במקום הבלוק הישום של אותו קובץ, אלא בצד. הבלוק הישן ממשיך להיות זמין דרך הצילום הישן, ומי שעובר כרגיל ניגש לבלוק החדש.
אפשר לשמור צילומים כאלו בכמויות, והמקום שהם תופסים הוא רק ההבדל בין צילום לצילום שקדם לו (או בין המצב הנוכחי של מערכת הקבצים אם הצילום הוא האחרון).
מגניב בשביל גיבויים, אפילו אוטומטיים. אפשר להגדיר בקלות רבה את אופן-סולאריס לקחת צילומים כאלו כל רבע שעה. חשבו כמה שזה מגניב לדעת שתמיד יש גיבוי של מה שעשיתם.
מה עוד?
לא צריך להסתבכך עם מחיצות, מערכות קבצים, פירמוטים, RAID וכל העניינים האלו.
ZFS תומכת בהכל, עם שתי פקודות אינטואיטיביות – zpool וzfs. היא תומכת גם בNFS (שיתוף קבצים פשוט ברשת).
אני לא אכנס לעובי הקורה בפוסט הזה, אולי בפוסט אחר, אבל מספיק שאומר שמערכת הקבצים הזו לבדה היא סיבה מספיק טובה לעבור מלינוקס לאופן-סולאריס (למרבה הצער, הרשיון בה משוחררת ZFS לא תואם את GPL, ולכן אין ZFS בלינוקס – ולא, אני לא מחשיב פתרון ZFS מבוסס FUSE כפתרון אמיתי).
המחשב שבסלון משמש אותי כמרכז מדיה, אני רואה בו סרטים שומר בו קבצי וידאו ומוסיקה, תוך שאני משתמש בבוקסי.
אבל מה, אין בוקסי בסולאריס. ולא בא לי לבזבז שבועיים במקרה הטוב כדי לגרום לבוקסי להתקמפל ולרוץ בסולאריס.
אז איך נהנים משני העולמות?
תוכנות לינוקס, איכסון באופן סולאריס?
האופציה המתבקשת היא לארגן מכונה נוספת שתריץ אופן סולאריס, ותשמש כמכונת אחסון בלבד.
הגישה תתבצע דרך NFS או דרך CIFS למחשבי חלונות (אני עדיין משחק על חלונות!).
וזה מתקשר לאגדה המקדימה על המכונה זוללת הביטים, שהיום זוללת בעיקר אבק.
התוכנית היא לקנות לה עוד קצת זכרון (ג’יגה אחד התקלקל וארבע ג’יגה היום עולה כל כך זול שזה פשע לקנות שני ג’יגה), לקחת איזה הרדיסק או שניים או שלוש מהמחשב בסלון, לקנות עוד איזה הרדיסק או שניים, ולקנפג שם אופן סולאריס עם ZFS בתצורת RAIDZ (תצורה יותר טובה מתצורת RAID5 שנותנת עמידות נתונים זהה אבל גם עם דיסקים זולים ובביצועים יותר טובים ברוב המקרים).
ככה המכונה תזכה לעדנה מחודשת, ולי יצא להנות מהתכונות של ZFS. אולי אני אפילו אשים את ספריית הבית שלי על המכונה הזו. עם חיבור ג’יגה ביט, זה כנראה יהיה יותר מהיר מעבודה מקומית על דיסק בודד כי אני אקבל את הביצועים של עבודה על כמה דיסקים במקביל.
בקיצור, אני מתחיל להזמין חומרה.
אני מניח שיהיו פוסטי המשך.. בהמשך.
קיבלתי את האימייל הבא מהצוות שמנהל את אתר ההרחבות של ג’ומלה, שאומר בקצרה שמ 1.7.2009 רק חבילות ברשיון GPL יכללו במאגר ההרחבות של ג’ומלה.
הוספתי את פיירסטטס למאגר ההרחבות לפני שנתיים וחצי, והמערכת קיבלה יופי של תגובות ממשתמשי ג’ומלה.
מכיוון שפיירסטטס לא משוחררת תחת GPL, היא כבר לא מופיעה במאגר.
בבדיקה מול גוגל-קש, מספר ההרחבות במאגר ירד מ4554 ל2990, ירידה של 33%.
לדעתי זו חוצפה ובריונות של של ג’ומלה לדרוש ממפתחי ההרחבות לשנות את הרשיון, וויתרתי על שרותי אתר ההרחבות של ג’ומלה (שזה די חבל, כי הוא הכיל 21 ביקורות על פיירסטטס, רובן המכריע מאוד חיוביות).
האימייל, תגובתי למטה:
Dear “Omry Yadan”,
We at the Joomla Extensions Directory want to remind you that, as announced 6 months ago, on 1 July are going to change the directory policy to list GPL Extensions only. As always, commercial and non commercial extensions are welcome on JED as long as they use the GPL license.
This change is intended for to bring it into line with the overall mission of the Joomla Project. After careful thought and reflection, the Joomla! Project determined that the Joomla! Extensions Directory should be a community resource that fully embodies the project’s values, especially freedom as exemplified by the GPL license.
Policy changes
We have implemented some policy changes to
- Enhance support of GPL developers
- Address concerns about relicensing.
We think that the best place to get an extension is from the original developer of that extension. Therefore we will not link to collections of GPL extensions that are not submitted by the original developers. These are not requirements of the GPL license but rather fall in line with our “forking” guidelines.
Forked projects … Non-GPL extensions
In order for you as developer to keep a non-GPL extension listed you need to relicense it to GPL.
You do it through to add two elements to each source file of your program:
- a copyright notice
- statement of copying permission, saying that the program is distributed under the terms of the GNU General Public License - http://www.fsf.org/licensing/licenses/gpl-howto.html
- adding a <license> tag to the header of the extension XML file
- including a copy of the GPL license in your distribution. This does not need to be copied to the user’s server on install, but must be included in the distribution.
Note for GPL extensions:
- You need to state on your website that the extensions are distributed with the GPL license
- You can’t add any conditions that restricts or contradicts the GPL license.
We thank you for your patience during these transitions. We will extend any assistance possible to making the transition as painless as possible for everyone involved. The project is committed to providing the information and help that developers need in order to relicense (or to license for the first time, if there is no current license).
The JED editors and members of the Core Team and Open Source Matters board are ready to advise or assist any developer who would like this help. If you have any questions about licensing or want help, then you can contact OSM with the following email address license@opensourcematters.org or the JED editors team@extensions.joomla.org
Some frequently asked questions
What if I have some GPL and some non-GPL extensions?
This policy refers only to those extensions listed in the JED. Your GPL extensions are permitted to be listed on the JED but your non-GPL extensions are not.
Where can I get information about how to license my product using the GNU GPL?
Every copy of Joomla includes a copy of the GNU GPL with instructions for licensing in the license.php file. Instructions are also available from the Free Software Foundation.
All you need to do is add two elements to each source file of your program: a copyright notice (such as “Copyright 1999 Terry Jones”), and a statement of copying permission, saying that the program is distributed under the terms of the GNU General Public License. (Free Software Foundation)
Can I use GPL v3 to license my extension?
Yes. In particular, you may need to use GPLv3 if you rely on certain third party libraries or APIs for your extension.
Can I use libraries in my GPL extension that are GPL compatible?
Yes.
What GPL version is Joomla! licensed under?
Joomla! is licensed under GPL version 2 or later.
Why are only GNU GPL licensed extensions being listed?
The simple answer is, making the JED a GPL only resource is the easiest and most practical solution. It frees the JED team from having to investigate or worry about licensing issues. It frees OSM from having to create and maintain a list of one or more acceptable licenses. When you break it down, other licenses were created because they opposed one or more parts of the GPL. The only license that truly embodies the spirit of the GPL is the GPL. Throughout the Open Source world, there is plenty of disagreement over what that spirit is and there is even more disagreement over what licenses are compatible and incompatible. In the end, our list of compatible licenses might be very different from yours. Our list of licenses that share the spirit of the GPL will most certainly be different than yours. So, we could waste months of time researching a list and debating which licenses should be included and excluded or we can make it simple and easy to understand for the community, the developers, and the JED team so that we can use those precious months to focus on the real point of this project: making great software.
Can I use a GPL compatible license?
The JED will only list extensions licensed using the GNU GPL.
What if I think my extension doesn’t violate the Joomla! license?
This is a policy in favor of software freedom and the mission, vision and values of the Joomla! Project, not one about technical issues in licensing.
…
What does this mean for enforcement of the Joomla! license more generally?
Enforcement of the Joomla! license is a separate issue from the policies of the JED.
If you have relicensed in recent days, thank you for your cooperation.
…
תגובתי:
First of all, I am both a user and a developer of several open source projects (some of which are using GPL, although I generally prefer BSD now because it puts less constraints on the end user).
the way I see it, you are trying to FORCE me to change my license, and I find this unacceptable.
FireStats is not a Joomla plugin, it’s a full fledged application that happen to support Joomla (and many other systems).
If I will dance to the tunes coming from WordPress, Jooma,Drupal or any other supported app, I will never get anywhere.
I am sorry, but I have no intention of changing my license.
feel free to remove FireStats from the Joomla extentions directory.
if I decide to re-license it under GPL I will list it again.
it is a pity because FireStats got great feedback from the Joomla community, but I am not going to step over my principles because of this.
the license under which I decide to release my software if my own decision, my mine alone.