קטגוריה: מסדי נתונים

מציאת רשומה לפי התחלה מדוייקת ב PostgreSQL

הנה בעיה מעניינת – כיצד אני מביא רשומה המתאימה ביותר להתחלה כלשהי, כאשר ההתחלה משתנה באורך/תווים שלה?

בשביל להיות פחות כללי, אציג את הבעיה כך:
יש לי קידומות של מספרי טלפון ואני צריך למצוא מי ספק הטלפון שמחזיק בקידומת הזו.

כאשר אני יודע כי 2 תווים ראשונים מחזיקים תמיד בקידומת הבעיה מאוד פשוטה – אני חותך 2 תווים ראשונים ומחפש עליהם קידומות בצורה חד חד ערכית, ואם מדובר ב unique index חיפוש מהיר ביותר שאולי יעשה sequence scan במקום חיפוש באינדקס ויהיה מהיר מאוד.

אבל כאשר חלק מהקידומות הן בעלות 2 תווים, חלק אחר בעלות 3 תווים ואפילו ישנן קידומות בעלות 4 או 6 תווים כאשר התו האחרון הוא זה שמבדיל בין ספקיות שונות יש בעיה.
הרי אין לי ידע מקדים מה הקידומת ומה הוא המספר עצמו.

למזלי יש כלים מאוד חזקים המסייעים בזה עם מסד נתונים PostgreSQL או PG בקיצור.

הדגמה של טבלת קידומות:

להמשיך לקרוא

מתכנת IT

הרבה שנים שאני מנסה להסביר לאנשים מה המקצוע שלי. אני מנסה להסביר כי המקצוע שלי הוא "מתכנת IT", אבל אנשים חושבים כי אני מדבר על DevOps.
התשובה היא לא, זה לא DevOps.

תנו לי רגע להסביר מה זה בעצם IT, שכולם אוהבים להתייחס אליו.
IT הם ראשי תיבות של Information Technology. כלומר מי שמוגדר כאיש IT, מתעסק בטכנולוגיות העוסקות במידע.

עכשיו אשאל אתכם שאלה: האם איש DBA שייך לקבוצה הזו? התשובה היא כן. האם הוא איש DevOps? התשובה היא לא.

המונח של DevOps התחיל כאיש פיתוח אשר יודע לגעת בהרבה רבדים של תוכנה וחומרה, אבל כיום מתייחסים אליו בעיקר כסוג של מנהל רשת אשר יודע גם לכתוב קצת קוד, ולכן אני לא נכנס להגדרה הזו.

אני יודע לגעת בציוד רשתות, אבל זו לא המומחיות שלי. אני הרבה פעמים צריך מישהו בעל ידע ורקע בנושא שיסייע לי בדברים מעט יותר מתקדמים שקשורים לדרך שמערכת מסוימת עובדת בה.

למשל אני יודע כיצד מסדי נתונים שונים עובדים, אני יודע להשתמש בהם, ולנסות ולגרום להם להיות יעילים, אבל אינני מומחה במסד נתונים מסוים, או מבין עד הסוף את כל הניואנסים שיש לסוג מסד נתונים מסוים להציע. זה התפקיד של איש DBA, הוא "חי" את העולם הזה, ומתמקד רק בזה, קורא את זה מהבוקר ועד הערב.

איש DBA יודע למשל המון על IO ועל דיסקים, וזיכרון, אבל זה לא אומר שהוא יודע מספיק בשביל להחליף ציוד, או לבחור חומרה בצורה נכונה. הוא רק יודע מה מסוגל לתת ביצועים טובים, אבל האם לוח מסוים עדיף? האם שרת מסוג מסוים? האם בקר מסוים? האם מעבד מדגם אחד טוב יותר וכיוב', הם פחות מהמומחיות שלו. זה לא אומר שהוא אינו יודע, זה אומר שהוא פחות חי את זה. זה יותר סוג של by-product של העבודה, מאשר המומחיות.

להמשיך לקרוא

ניסויים בתורי הודעות

יש מערכת שאחרי load test הבנתי כי אני חייב לבזר את המערכות שבה. אז התחלתי לבצע מחקר על סוגים שונים של message queue בשביל לבזר את המערכת. עשיתי ניסויים עם המון מערכות שונות, כולל התייעצות עם אנשים שממשים כבר מערכות המשתמשות בהם, והגעתי להבנה כי כנראה ש RabbitMQ מתאים לצרכים שלי.

התחלתי לממש את המערכת ותוך כדי, מצאתי את הפוסט הזה של חברת קפריזה.
קשה לי עם מה שכתוב שם. מצד אחד זה מפחיד מה שנכתב, מצד שני, מה שנכתב לא רציני באמת.

למשל כתוב שם שהם לא ניסו להתאים את Rabbit לצרכים שלהם, ואחד הדברים שאני למדתי בדרך הקשה, היא שאפילו המערכת הידידותית ביותר, במידה ולא מותאמת לצרכים ולמשאבים שיש לי, לא תשתמש בהם נכון. אבל הם העדיפו להשקיע יותר זמן בלכתוב ספרייה חדשה מאשר בללמוד קצת את ההגדרות של Rabbit, אשר בקריאה די מהירה מראה שהוא מסביר איך תכנון המשאבים שלו עובד.

למשל אני עשיתי 2 הגדרות בלבד לRabbit להתאים למכונת הפיתוח החלשה שלי, והגעתי ללמעלה מ7 מליון בקשות בשניה אחת, עד שרוחב הפס נחנק, אבל ה load היה על 0.02 לאורך זמן רב. כלומר לא הגעתי ל load שהם דיברו עליו. אבל יכולתי לבדוק לאורך זמן, רק כאשר ירדתי בערך ל5 מליון בקשות בשניה, ואז הרוחב פס כבר לא נחנק לי.

מצד שני, כתבתי את המערכת שלי בגו, ויותר מזה, מי שמדווח ובנוסף מי שמקבל את העבודה לא היו על אותה המכונה, אלא בכלל על הדסקטופ שלי בו זמנית, והload במכונה שלי, לא היה יותר מאחוז (כשהמכונה שלי עוד עשתה הרבה דברים נוספים).

יותר מזה, בתיעוד של Rabbit, כתוב שאפשר להגביל את ה load על המכונה, במידה ועוברים כמות מסויימת של שימוש במשאבים, היא מפסיקה לקבל עבודות, דבר שגם לא הוסבר אם נכנס לבדיקה שלהם, אך אני בכלל לא הגדרתי אותו.

כך שלי חסר מאוד מידע איך ומה בוצע בפוסט, אבל אני לא מצליח לשחזר את מה שהם כן מזכירים.
העניין הוא, שאני לא בוטח ברדיס לפעולות ה mq שאני צריך, כי אני צריך מחסנית יציבה של worker..
אם חלילה וחס הוא נפל, אסור שהמידע יאבד, ויותר מזה, במידה ואני צריך להוסיף workers, אני צריך מצב של ביזור המידע, בלי שworker אחד ידרוך על השני, ואני מקבל את זה בצורה טבעית ב Rabbit, (ועוד מספר סוגים של MQ שבדקתי), אבל רדיס מעולם לא תוכנן לזה. הוא נמצא בזיכרון, אני כמובן שיכול להכריח אותו לכתוב לדיסק (איטי מאוד, אבל זה מה שקורה עם persistence queue בRabbit), אבל בשביל לעשות תורים בגישה של Round Robin, ובכן, בלי לכתוב משהו ב lua, אני לא מכיר תמיכה לזה ברדיס, למרות שאשמח לגלות שיש.

ככול שאני עובד כרגע (אמנם עדיין בפיתוח) עם MQ, ככה אני אוהב יותר את הרעיון של השימוש ב Rabbit.
במערכת שאני בונה, יש לי מערכת חיצונית שהיא של ספק אחר שמדברת עם HorentQ, דרך הפרוטוקול שנקרא STOMP (בניגוד לRabbit שברירת המחדל שלו היא AMQP אך תומך גם ב STOMP), והיתרונות של מערכת כזו שהיא robust מאוד, מאפשרת להתמודד עם בעיות שונות, כדוגמת קריסת מערכת, ניתוק התקשורת, התנהלות של load balance של מספר שרתים וכיוב'…

כך שלדעתי, אחרי הרבה ניסויים, אני חושב שRabbit זו הגישה המתאימה לי, ובמידה ולא, תמיד אפשר לעבור בלי להחליף קוד 🙂

 

 

אנשי DBA

לאחרונה יוצא לי לבצע המון אופטימיזציות למידע, אשר במקור הטבלאות בו לא תוכננו שיהיו בו כל כך הרבה רשומות (יש לזה המון משמעויות מהמון צדדים ובחינות), ויוצא לי לשבת עם הרבה אנשים המתיימרים להיות אנשי DBA, ואפילו כמה שהם באמת כאלו.

הבעיה בשוק שלנו, היא שמרבית האנשים המדווחים כי הם מומחים למשהו, במקרה הזה – DBA, אינם באמת מומחים, וחלקם הגדול גם לא מבינים מעבר לאיזה קורס וקריאה של התעוד הרשמי.
רובם אפילו לא עשו ניסויים על התמודדויות של בעיות כדוגמת מה קורה כאשר באמצע כתיבה התקשורת נופלת, או יש בעיה בדיסק, או איך להתמודד עם כך ש slave לא מצליח לשמור את הנתונים, שלא לדבר על כך שיש journal שנכתב והוא מה שנקרא, והרשימה עוד ארוכה.

אני רחוק מלהיות איש DBA, אך חשוב לי תמיד להבין איך דברים עובדים ולמה, אז אני גם קורא את התיעוד המקורי, אבל גם עושה ניסויים, מפיל דברים וכיוב', וככה לומד דברים.

אבל אותם אנשים המתיימרים להיות אנשי DBA, הם חסרי ניסיון מעבר למה שמתועד, הם לא באמת יודעים דברים מניסיון, או ניואנסים קטנים מאוד שרק מי ש"חי" את המקצוע מקבל אותם.

למשל בכל מסדי הנתונים שאני מכיר, יש בעיה עם Foreign keys. הם נשמעים טוב, אבל מוסיפים סיבוכיות בכך שהם בעצם מתורגמים לעוד פעולת select. את בעיית הביצועים הזו גיליתי לבד, את הסיבה לכך, ובכן איש DBA הסביר לי. אבל הוא באמת מבין המון דברים. הפתרון לכך פשוט, אבל זה לא נושא הפוסט 🙂

אבל הנה בעיה קשה: מכירים את MySQL ?
אתם יודעים כי הוא לא באמת תומך בפעולות join ?
כן, אני יודע שיש לו תחביר לכך, אבל אני מדבר על מה שמתרחש מאחורי הקלעים בשביל לספק אותם. זה הניואנסים הקטנים שאני מדבר עליהם.
העניין הוא שמסדי נתונים שונים, ואפילו גרסאות שונות של מסד הנתונים שעובדים בו מתנהגים לגמרי שונה.
לפעמים גרסה אחת תכיל המון בעיות שגרסה קודמת או חדשה יותר תפתור, אבל בלי הניואנסים האלו, איך תדעו להתמודד עם הדברים?

ואז אני התחלתי לשאול את עצמי את השאלה, האם אני כאדם המתעסק המון עם מסדי נתונים כמתכנת, מקבל על עצמי אחריות של ללמוד את הכלים וההתנהגות של הדברים, או האם אני חייב להיות תלוי בעוד אדם בנושא, אשר מאוד קשה למצוא והדרך היחידה כאן היא לדעת לפחות ברמה הקיימת האם יש ידע בנושא או לא.

דעותי עדיין חלוקות, ואשמח לשמוע מה לכם יש להגיד בנושא.

Firebird 3.0

כתבתי והזכרתי כאן המון פעמים את Firebird – הלא הוא מסד נתונים חופשי לגמרי וחוצה פלטפורמות עם המון עצמה וכוח.

למשל, שלומי נוח, איש DBA מומחה MySQL, רשם בתחילת השנה העברית החדשה, כי הוא רוצה מסד נתונים שבו ניתן לקבוע עם כמה מעבדים ניתן לעבוד, ובכן Firebird תומך בזה כבר מספר שנים.

לFirebird יש מספר תחבירי SQL, וחשוב להבין אותם לפני הבנה של התכונות החדשות. סוג התחבירים הם:

  • DSQL
  • ESQL
  • PSQL

DSQL – הם בעצם השאילתות שכותבים ומריצים בצורה דינאמית באמצעות API. המקדם D מייצג את המילה Dynamic.
ESQL – הם בעצם שאילתות עם preprocessor, כאלו שכותבים למשל דרך תוכנה שלנו. ההבדל בינה לבין DSQL היא שבשפה זו משתמשים בפקודה EXEC. הפירוש של המקדם E מייצג את המילה Embedded.
PSQL – השפה שבה כותבים stored procedure וטריגרים. המקדם של P מייצג את המילה Procedural.

בנוסף ישנה שפה בשם DDL – ‏Data Definition Language. זו השפה בה עושים פעולות כדוגמת create table או create database.

לאחר הסבר קצר על התחביר, ניתן להבין פיטצ'רים שונים ולאן הם שייכים.

גרסה 3.0 של Firebird שכרגע בזמן כתיבת הפוסט, עדיין נמצא בשלבי בטא, וב2015 צריכה להשתחרר, מביאה איתה המון חידושים ותוספות מעניינות.
הנה רשימה חלקית בלבד של אותם התכונות החדשות:

SQL – כלל השפות:

  • Merge Syntax
  • פונקציות window
  • תמיכה ב regex בביצוע SUBSTRING
  • נכנס סוג נתונים בשם Boolean
  • יכולת לשמור גרסאות עם RDB$RECORD_VERSION
  • cursor יציב

PSQL:

  • פונקציות SQL
  • פרוצדורות
  • טריגרים, פונקציות ופרוצדורות משפות חיצוניות
  • חבילות
  • חריגות עם פרמטרים
  • SQLSTAT במצב של WHEN
  • שימוש ב continue בתוך לולאות.
  • cursor יכול להחזיר התייחסות כמשתנה מסוג רשומה
  • cursor דו כיווני

DDL‏:

  • תמיכה במצב null של עמודה ו domain
  • היכולת לשנות קידוד ברירת המחדל של מסד הנתונים
  • הוספה של Identity Column – המקביל ל serial בPG ו Auto Increment של SQLITE ו MySQL
  • תחביר עבור RECREATE SEQUENCE/GENERATOR
  • טריגרים עבור DDL
  • תמיכה ב DATABASE LINGER

אבטחה:

  • תמיכה database encryption
  • תמיכה מורחבת יותר בהרשאות Object
  • הרשאות לעבודה עם DDL
  • הרשאות ברמת מסד הנתונים
  • תוספות לעבודה עם Roles

פיקוח:

  • הוספת יכולות נוספות לסטטיסטיקה אודות שאילתות ומסד הנתונים בכלל

אז מה זה כל הסעיפים האלו ? להמשיך לקרוא

anti patterns של מתודולוגיות עבודה

הפוסט המקורי לא הובן כפי שהתכוונתי אליו, ולכן שכתבתי את הפוסט לגרסה הזו.

הקדמה

ישנו מושג הנקרא anti-pattern. פירוש המונח, אם נשתמש בוויקיפדיה: "אירועים חוזרים ונשנים של פעולות אשר בפועל אינן יעילות והרבה פעמים בלתי מועילות."
לא תמיד הפעולות שאנחנו מבצעים נראות כ anti-pattern, אך כאשר אנחנו מסוגלים לבחון אותן לעומק, אנחנו מגלים שהם כאלו.

הדגמות

להמשיך לקרוא

Firebird וליברה אופיס

Firebird הוא מסד נתונים חופשי עם המון יכולות, מאוד יציב, והוא מקבל יכולות נוספות כל הזמן. הוא מאוד אמין, ויש מערכות BI שונות, מערכות רפואיות ומערכות קנייניות אחרות המשתמשות בו.
הוא מסוגל לעבוד כשרת (ניתן גם לבחור כיצד השרת יתפקד), אך גם כמסד נתונים embedded.
הוא עם footprint יחסית קטן למשאבים (מול מה שהוא מספק), ויודע לנצל את המערכת עד הסוף בשביל התמודדות עם מידע. כך שמערכת המסוגלת לספק מענה לקבצים בטרות, Firebird יודע להתמודד עם זה בהתאם.

אישית, הוא תמיד ההתלבטות שלי לבין PostgreSQL, כי למעשה שניהם מתחרים, בניגוד לMariaDB/MySQL אשר לדעתי אינם באמת מספקים את הסחורה.
עד עכשיו הוא זכה להמון התעלמות דווקא מקהילת קוד פתוח ותוכנה חופשית, בניגוד לעולם הקנייני, אך נראה כי זה משתנה.

ביולי 2013, פרסמתי כי Base מקבל תמיכה בFirebird כחלק מפרוייקט SOC.

החל מגרסה 4.2, במידה ומפעילים תמיכה ביכולות נסיוניות, ניתן לקבל תמיכה בFirebird כמסד נתונים embedded עבור Base.
libreoffice base firebird בשביל לקבל תמיכה בדברים ניסיוניים בליברה, פשוט הולכים בתפריט ל Tools משם ל LibreOffice, משם ל Advanced ולוחצים על Enable experimental features.

כרגע מחכים כי גרסה זו תתייצב, ואז לגרום ל HSQLDB לצאת לגמלאות (בכל מה שקשור לגרסת ברירת המחדל של ליברה), וגם לספק כלי המרה ממנו אל Firebird.

ישנם המון סיבות לבצע את זה, כמו הצורך לגרום למנוע מבוסס ג'אווה לעבוד עם ++C, וכן התנהגות ומהירות אשר נפגמת בשימוש.

לאחרונה, גם נראה כי מפתחי Kexi כבר מדברים על הוספת מנוע  embedded של Firebird, אפילו ניתן לראות כי זה מופיע ברשימת הדריברים במימוש.

Sequel וPostgreSQL

לאחרונה אני מוצא את עצמי משתמש בתכונות מאוד מתקדמות של PostgreSQL, שחלקם נוספו רק ב9.2 (למשל range). העניין הוא שאני עובד עם רובי ו Sequel, ולרוב אנחנו שמים לב כי ORM אינם אוהבים דברים שהם לא סטנדרטיים.

אז Sequel מכיל גם חלק של תוספים. החלק הזה מאפשר לנו להשתמש עדיין בגישת ה ORM אבל לדברים שהם עבור מסד נתונים ספציפי.

ישנם שני דרכים לטעון תוספים:

  1. דרך גלובלית
  2. דרך שתופעל רק על החיבור שלנו

הדרך הגלובלית נראת כך:

Sequel.extension(:core_extensions, :pg_range, :pg_array)

הדרך של החיבור, נראת כך:

DB.extension(:pg_range, :pg_array)

כאשר יש דברים שהם קשורים לחיבור מסויים, טעינה גלובלית לא תתפקד, וכאשר יש דברים כלליים מידי, טעינה לפי חיבור לא תינתן.
בשני המקרים, כאשר לא ניתן להשתמש בהם, תחזור לנו חריגה בנושא.
שימוש ביכולות של Range, יהיו למשל:

DB[:readers].where(Sequel.pg_range(:comments_id).contains([10, 15, 1900])).sql
# SELECT * FROM "readers" WHERE ("comments_id" @> (10, 15, 1900))

והנה יש לנו שאילתא אשר משתמשת ב Range של Pg, אבל כתובה עם ORM.
בתעוד כתוב שגם שם השדה יכול להיות המקור של pg_range (למשל), אבל אצלי זה לא כך (גם אם זה גלובלי).

למערכים, הפעולה מאוד דומה גם כן:

DB[:comments].where(uid: 10).where(Sequel.pg_array_op(:comments).contains(Sequel.pg_array([15,23]))).sql
# SELECT * FROM "comments" WHERE (("id" = 1) AND ("comments" @> ARRAY[15,23]))

קריאה נוספת:

כשיש לך פטיש אוויר ביד …

לפני מספר חודשים עשיתי פרוייקט עם מישהו שהעסק שלו הוא פיתוח מערכות על wordpress.
הייתי צריך לבנות לו מערכת מבוססת טלפוניה לעסק שלו, עם ממשק ניהול למספר דברים, משהו כמו 3 מסכי ניהול, ובנוסף מספר ניתובים לשמור ולמשוך מידע.

כאשר אותו בחור הבין שבחרתי בסינטרה ולא ב wp, הוא לא הצליח להבין מדוע לא לבחור ב wp, היות ולדעתו ניתן לעשות עימה הכל.
ניסיתי להסביר לו כי מדובר בoverkill עצבני, כלומר לקחת פטיש אוויר לעשות חור בקיר לתלות תמונה, כאשר מסמר פשוט עם פטיש קל מספיק, הוא עדיין לא הבין את הבעיה, הרי אפשר לעשות אתרים ממש גדולים עם wp, אז מדוע אי אפשר לקחת אותו בשביל משהו פשוט ?

ובכן, עצם העניין שהכלי תוכנן ליצור אתרים ממש גדולים, הוא אינו יעיל או מותאם לדברים קטנים. הוא תופס יותר מידי משאבים לזה, אשר לא צריכים להתקיים כאשר מדובר במשהו קטן.
כאשר צריך ליצור גמישות רבה מאוד, לפעמים האנרגיה שתדרש בwp תהיה גבוהה יותר מאשר ליצור אותה מאפס, רק בגלל שמערכת cms במקור אינה זקוקה לזה, אז לא תוכננה בחשיבה הזו, בעוד שחשיבה מראש על מימוש מסויים, תיצור תשתית טובה יותר.

שימוש בסינטרה מאפשר לי לקחת פריימוורק כדוגמת foundation או bootstrap כ css ובנוסף לשלב את ember/angular או סתם את jquery/dojo בהתאם לצורך.

עבור מסדי נתונים, אני גם מקבל גמישות, כך שאם חלילה וחס אני נאלץ לגעת ב MySQL/MariaDB (לרוב להתחבר למסד נתונים קיים) אין בעיה (לפחות ההתחברות, עם הגועל זה משהו אחר), ואם אני בר מזל ויכול לבחור מסד נתונים, אז אבחר ב PostgreSQL , ואם יש צורך אז אבחר בכלל במונגו או אולי בכלל בRedis ?

אם אני צריך, אז אוסיף למשל סוג של job queue בהתאם לצורך הספציפי והרשימה לעבודה עוד ארוכה…

כל אלו אינם קיימים בwp, היות ובתור cms הוא נועד לגישה מאוד מדוייקת שמתאימה ל cms, אבל לא אפליקצייה.

אבל כנראה גם הפעם מאסלו צדק, וכשיש  לך פטיש ביד, הכל נראה לך מסמר …

ניתוח כושל והתמודדות עם מסד נתונים בעייתי

חבר עובד על מערכת שהוא בונה, ומשתמש ב Firebird כמסד נתונים שהוא embedded, אך הוא ביצע טעות בטבלה שיצר, ורצה למחוק אותה אבל גילה כי אינו יכול.

בהתחלה Fb דיווח כי האינדקס נמצא בשימוש ולכן לא ניתן לבצע את הפעולות, והסתבר שהיו מספר פרוססים אשר ניסו לבצע את פעולת המחיקה. אינני יודע כיצד הגיע המצב.

כאשר הוא קרא לי לסייע לו, זה היה המצב עצמו שגיליתי שקרה. והתחלתי לנסות להבין מה קורה.
גיליתי כי מספר פרוססים שונים נעלו את הטבלה בניסיון לבצע עליה מחיקה, אך איכשהו יש race condition לא ברור על הפעולה. הכרחתי אותו לסגור את כל מה שנוגע בקובץ.

לאחר סגירת כלל הפרוססים, המנוע התלונן על בעיית הדפים. הוא אמר שרשום לו הגדרה שיש 0 דפים למסד הנתונים, כאשר הוא צריך מינימום של 6. כלומר, למיטב הבנתי, היו מספר פרוססים שפיזית התחילו בכתיבה באותו הזמן, כאשר לא היתה נעילה ולכן הjournal כתב מידע לא נכון. אינני יודע למה, היות וACID אמור למנוע זאת, אך זה קרה.

אולי היו מספר ניסיונות הסרה ללא commit וזו היתה הבעיה, אך שוב, הוא לא ידע להסביר לי בדיוק כיצד הגיע למצב הזה.

ניסיתי לתקן את הבעיה בהתחלה עם gfix, אך הוא לא הצליח לתקן את המצב, והבעיה נשארה, אז החלטתי לנעול את מסד הנתונים באמצעות הפקודה:

$ gfix -shut -user sysdba -password masterkey <database>.fdb

ואז להעזר ב gbak אשר מאפשר לעשות גיבוי "חם", כלומר בזמן שדברים בד"כ רצים, על ידי יצירת מצב של snapshot לדברים, אך ללא שימוש ב Garbage Collection:

$ gbak -b -g <database>.fdb

ביצוע שחזור מה snapshot למסד נתונים חדש פתר את הבעיה. המידע ניצל, ועכשיו ניתן היה להסיר את הטבלה הסוררת:

$ gbak -c database.gbak  db2.fdb

ב firebird למי שאינו יודע, יש טבלאות פנימיות, חלקן שומרות audit על כל פעולה, כולל חיבורים, למסד הנתונים, פעולה אחרונה, וכיוב' …
אך המידע שם לא הצליח לסייע לי.
אז ניסיתי לפנות ללוגים. ניתן לגרום לFb ליצור לוג פר חיבור משתמש, אך הסתבר כי הוא לא הגדיר כזה, ולכן לא היה ניתן בכלל לראות פעולות ישנות בלוגים.

למעשה הכל נשאר בברירת המחדל, כך שבמקום ליצור סביבה הנוחה לדיבוג מידע בזמן פיתוח, הוא השתמש רק בברירת המחדל וחבל.

דברים שמעצבנים אותי ב PHP ו MySQL

הקדמה

זה לא סוד שאני לא סובל את PHP. בראש ובראשונה זו לא שפה, אלא אוסף פאטצ'ים ליצור templates עבור עולם הweb. ההתחלה של "תכנות" עם PHP מאוד פשוטה, אבל ליצור משהו שעובד טוב, יעיל ובטוח, ובכן זה כבר סיפור אחר.

זה גם לא סוד שאני לא סובל את MySQL. וכשאני מדבר על MySQL כאן, זה על המכלול הגדול של הפרוייקטים, כולל  MariaDB אשר לא פתרו בדיוק את הבעיות השונות, אלא רק ממשיכים לפתח עוד פיטצ'רים שונים.

משום מה, 2 הרעות החולות האלו הולכות "טוב" בייחד וניתן למצוא המון מערכות המשתמשות בשניהם ולכן אני גם כותב עליהם בייחד. אלו לא כל הדברים שמעצבנים אותי בהם, אלא רק דוגמיות קלות ביותר בנושא.
ופוסט זה משמש רק להוצאת קיטור שלי עם הצורך להשתמש בכלים האלו לאחרונה. להמשיך לקרוא

Sequel חלק שני

בחלק הקודם הצגתי על רגל אחת את הORM שנקרא Sequel והצגה של שימוש בסיסי בו.
בחלק זה, אנסה לתת לכם כמה דגשים על שימוש מעשי יותר בו.

מודל

Sequel תומך באפשרות ליצור מודל -> מחלקה שמייצגת טבלה. אם נחזור למסד הנתונים שיצרתי בחלק הקודם, ניתן ליצור מודל לטבלת Posts:

class Posts < Sequel::Model
end

זה כל מה שאנחנו זקוקים בשביל לגשת אל טבלת Posts. עכשיו התוכנית שלנו מההתחלה עד הסוף תהיה:

require 'rubygems'
require 'sequel'

DB = Sequel::Sqlite('blog.db')

class Posts < Sequel::Model
end

Posts.where('id > :id', 1000).delete

בהתחלה אתחלתי את Sequel, פעולה שלא ניתן לברוח ממנה.
לאחר מכן יצרתי את המודול שלנו (הוא חייב כבר גישה למסד הנתונים).
אחר כך, יצרתי תנאי שאומר להחזיר את כל הרשומות עם id שגדול מ1000, ואז למחוק אותן.
זו הדרך הנכונה ד"א לעשות דברים איתו, כלומר lazy loading של תנאי לפני הפעולה עצמה.

בעת חיפוש, במידה וארצה למשל, לקבל את השדה title, אוכל לעשות זאת כך:

Posts[:title].where(id: 1)

אך במידה וארצה להשפיע על מה יהיה בפעולת ה select, עם יותר משדה אחד, אוכל פשוט להשתמש בפעולה הבאה:

Posts.select(:title).where(id: 1)

יש עוד המון פעולות שמתורגמות למתודות בספרייה, אבל יש לה גם כלי עזר נוספים.
למשל, נגיד ונרצה לבצע pagination למידע.
כלומר נרצה לקבל כל פעם איקס כמות ערכים לדף. ולדעת להמשיך משם.
כאן אנחנו מרגישים את הספרייה יותר, היות ויש לה כלים אפלו לשם כך:

Posts.paged_each(rows_per_fetch: 25) do |row|
  p row
end

מה שקורה כאן הוא שבפועל ריבוי שאילתות המחשבות עבורינו את המידע,אך אנחנו מקבלים רק 25 תוצאות ל"דף".

עוד תמיכה מעניינת, היא לקחת מידע SQL ולקבל כלים שמאפשרים לבצע פעולות של Graph. כלומר מיפוי טבלאות וערכים בצורה של גרף. כלומר שיוך מידע בין טבלאות שונות, כולל האפשרות ליצור alias לטבלאות שונות בשביל להביא את המידע בפועל.

בחלק הבא אדבר על התמיכה בjoin כחלק מתחביר ואסיים עם הסבר על תמיכה בmigration ובשורת הפקודה אשר נקראת sequel.

Sequel חלק ראשון

הקדמה

נכתבו עבור עבודה בשפת רובי מספר ספריות ORM. הספרייה המוכרת ביותר (ובעיני הבעייתית ביותר) היא ActiveRecord המגיעה כחלק מ Rails, אך עומדת גם בינה לבין עצמה.
ספריית ORM אחרת שאני מחבב בערך מהניסוי השני שלי (בניסוי הראשון לא הבנתי אותה), נקראת Sequel.

היא עובדת מצד אחד בגישה שונה מActiveRecord, כך שלהגר אליה אינו דבר של מה בכך, אך לאחר שמבינים אותה, מגלים ספרייה עם יותר כוח, אבל בעיקר שכתובה ועובדת נכון יותר (לדעתי).
ביולי הספרייה הגיעה לגרסה 4.0.0, והחלטתי שהגיע הזמן גם לדבר עליה, כאשר בחלק השני, אצור גם דוגמאות חזקות יותר, ואפילו כיצד יוצרים סוג של migration איתה כדוגמת צורת העבודה הנהוגה ב Rails.

על הספרייה

הספרייה מחולקת לשני חלקים:

  1. חלק ראשון הוא ה core, אשר עובד בצורה זהה, וזקוק מאחורי הקלעים לחיבור מסדי נתונים.
  2. החלק השני הוא חלק התוספים, אשר מסוגלים להוסיף לספרייה יכולות נוספות, אך צריך לאפשר אותם. לצערי עדיין לא התעסקתי עם חלק התוספים, ולכן נכון לפוסט זה, עדיין לא אוכל לכתוב עליהם דבר מה.

התקנה

על מנת להתקין את sequel, דבר ראשון נתקין אותו, ודבר שני את הדריבר הרגיל לחיבור מסד הנתונים:

$ gem install sqlite3 sequel

התחלה

להמשיך לקרוא

Firebird פוגש את ליברה אופיס

פרוייקט הפיתוח GSOC מבית גוגל כמובן, הביא לכך שנכון לשבוע שעבר, יש דריבר רשמי לFirebird בתוך LibreOffice Base.

הדריבר כרגע לא עושה כמעט כלום, כי זו רק התחלת הפיתוח, אבל הוא נבנה בעצם לאפשר לעבוד עם Firebird בתצורת Embedded כחלק מBase של ליברה.
כרגע אין תמיכה בקובץ חיצוני, או שרת חיצוני, אך מדברים על להוסיף תמיכה שכזו.

על מנת לגרום לו לעבוד בקובץ odb, יש לשנות הגדרות של

EmbeddedDatabases/DefaultEmbeddedDatabase/Value

מהערך של

sdbc:embedded:hsqldb

לערך:

sdbc:embedded:firebird

כמו כן, ניתן תמיד ליצור קובץ חדש ולהגדיר אותו לעבוד עם Firebird.

הבלוג המקורי בנושא. קוד המקור בgit.
 

ActiveRecord sucks (English)*‎

Every Ruby developer knows an ORM named ActiveRecord.
It is so common, that it has even implementation on different programming languages, such as PHP.

At one hand, it is written in a way that truly understand Ruby, but on the other hand, it is written very badly. It is written so badly, that it has a lot of SQLi bugs inside, it uses too many resources to perform tasks, and the list just goes on and on …

If that was not enough, then it is very opinionated on how things would be created, even on places that you need different level of thinking, it does not provide it on it's own, and you find yourself write stored procedures that implement them, or functions for triggers instead.

I mostly use Ruby "clean", that is not writing any web based application, and on one of the non web program that I wrote, I needed to go over million records per day (not literally a day, but day in BI), and I find that after 200 requests for records, it opens too many connections to the database, even though it has a limit for "only" 120 connections for it's connection pool, but when I decrease it for 50 connections, it claims that it does not have enough connections to use.
Even an hour of inactivity, it does not release it's connections back, even though it has a "timeout" of 30 seconds to release it.

It ignores my timeout settings, it just take more resources, but does not release them back, regardless of what I tell it to do. So it renders as resource hog, and you require to release the resources "by hand" rather then do it's job right.

I found, many complaints about it on the web, and even few bug fixes, that didn't really fixed anything as I can see in real life situation, even when going to the last stable release of it.

S I started looking at other ORM for Ruby (and there are others as well), and it looks like a problem only with AR so far.

* This is a translation that was requested by few people for the original Hebrew post.

ActiveRecord sucks

מתכנתי רובי (בין אם מסילות או לא), מכירים את ה ORM שנקרא ActiveRecord.
הוא כל כך נפוץ, עד שנוצרו לו אפילו חיקויים בשפות אחרות כדוגמת PHP.

הבעיה היא שהוא כתוב ממש רע. מצד אחד הוא משתמש בחשיבה של רובי בצורה באמת מטורפת, אבל הוא לא יעיל יחסית מבחינת משאבים, יש בו המון באגים שיוצרים SQLi ועוד בעיות אחרות בסגנון.
אם כל זה לא היה מספיק, אז בנוסף הוא יותר מידי דעתני גם במקומות שחייבים לגלות גמישות מחשבתית, ואני מוצא את עצמי מבצע הרבה דברים בטריגרים של מסד נתונים, למרות שהיה מתאים לעשות אותם יותר בתוכנה שלי.

למשל יש לי מערכת לא מבוססת web בשום צורה, שעובדת עם מליוני רשומות ביום. הבעיה היא שכבר אחרי 200 גישות למסד הנתונים, למרות שה pool מוגדר רק ל120 חיבורים, אני מגלה שנפתחו עוד חיבורים שלא נסגרים. אם אני מוריד את זה ל50, אז הוא מתלונן שזה לא מספיק, אבל גם אחרי שעה של חוסר פעילות, הוא לא מסיים את החיבורים למסד הנתונים, וזה למרות שמוגדר לו להחזיר את החיבור לאחר 30 שניות ללא שימוש.

לא משנה שהגדרתי לו timeout לכל פעולה, הוא לא משחרר, רק לוקח עוד. חשבתי שאני לא בסדר, אבל מצאתי כל כך הרבה אנשים שמתלוננים על זה כבר שנים, מה שהופך אותו ללא יעיל אם אין לי משהו שאני מריץ שיגרום לו לשחרר משאבים ידנית.

היו דיווחי באגים שונים, ו"תיקונים" והבעיה פשוט ממשיכה, לא משנה שאני תמיד מנסה לשדרג לגרסה הכי אחרונה.

אז התחלתי לבדוק ORM אחרים ברובי (כן יש כמה וכמה), ונראה שזו בעיה ייחודית ל AR בלבד.

My Database-free Application lecture

Today I gave a lecture about database-free applications.

Most people who first read the title, thought that "oh you probably write to memory or disk or something", yet the lecture is not about storing data, but on one approach of designing systems to work.

It is a completely different thing, yet I find that many people can't see it, they are looking for the "catch".

This post was written prior to the actual lecture itself (a day before in fact 🙂 ), so I can't tell if my lecture was good enough or not, but you have my slide notes, and the whole lecture (using html5 and reveal.js -> firefox or chrome recommended), so take a look and tell me yourself 🙂

My first python application

It's that time of the thing again – I'm required to learn new technology due to a project requirement.
The requirement is to write something using django, but I do not know django or Python.

So I've started my first project using the Python language, just to have a feel for it.

My first project is to convert my (in)famous quote file into a database, so I choose Firebird db for the task, using Python driver named fdb. It is very robust open source RDBMS, that many people over look, and choose unreliable RDBMS known as MySQL/MariaDB instead (but why ?!).
Here is the DDL of my database, it's simple as you can see, but has so much abilities 🙂

My code is not perfect, and require a lot more optimization, and polishing, but I'm getting there using the help of my friend – Meir, who loves the idea that a Ruby dev like myself arriving into the python world 🙂

בדיקות אוטומטיות אינן התשובות להכל

TDD – ‏Test Driven Development היא גישה או תפיסה האומרת כי כל שורת קוד אותה אנחנו מפתחים, אנחנו קודם יוצרים לה בדיקה שתיכשל, ואז כותבים את הקוד שיגרום לבדיקה לעבור, ובכך מונעים הרבה מאוד בעיות בפיתוח, וכן יכולים לזהות ריגרסיה כאשר זו מגיעה בקוד. כבר כתבתי על הנושא מספר פעמים כאן בבלוג.

לאחרונה היה באג בספרייה בשם ActiveRecord, אשר במצב מאוד מיוחד, היה ניתן לגרום למתודה find_by_‎ לבצע SQL Injection. הבאג ד"א היה ניתן לניצול רק במצבים מאוד מדוייקים של שימוש במתודות, ולכן אם לא היה שימוש בגישה מסויימת, לא היה ניתן לנצל אותם, אבל הבאג היה עדיין קיים, והמליצו לכולם לשדרג לתיקון הבעיה.

בגדול מאוד, הבאג התרחש רק במצב קיצון מסויים. הבאג מאוד "פשוט": הספרייה לא תרגמה תוכן כמחרזות, אלא פרשה את זה כאובייקט רובי, ואז היה ניתן להזריק קוד (בעיקר ל SQL). העניין הוא, כי במרבית השימושים במתודה, הבאג לא התקיים.

כלומר מרבית השימושים בActiveRecord מעולם לא היו גורמים לבעיות או מסכנים אתר מסויים ב SQLi. ועכשיו נשאלת השאלה: האם TDD מסוגל לעלות על מקרה קצה כל כך קיצוני ?

האם ב99.9 אחוז מהבדיקות שתעשה הבדיקה תצא תקינה, האם תדע לכתוב את הבדיקה 0.1 בה תצליח לגלות באג ?

לדעתי האישית, התשובה היא – כי לרוב לא. יש גבול לרמת הבדיקות שניתן לבצע בשביל לעלות על בעיות.
כלומר יש עדיין הרבה מאוד גורמים שלא ניתן לחשוב עליהם מראש שיכולים לגרום לקוד שלנו לדווח על באג, אבל לא ניתן לכתוב אין סוף בדיקות לכך.

בדיקות אוטומטיות כן חשובות, ואינני אומר לרגע אחד לוותר עליהן, אבל הן אינן תחליף לבדיקות נוספות, כדוגמת QA איכותי, וכן מבחן "המשתמש האידיוט" שעושה מה שבא לו בתוכנה, והתוכנה צריכה לדעת להתמודד עם זה.

בדיקות אוטומטיות בסופו של דבר באות להוכיח כי מה שבודקים באמת מתקיים, אבל הן אינן מוכיחות כי אין באגים בקוד, אלא העדר באגים במה שנבדק, אלא אם הבדיקה עצמה מכילה באג זה או אחר.

gbak ויכולותיו

ל Firebird ישנם כיום (החל מגרסה 2), שתי תוכנות לביצוע גיבויים של מסד הנתונים, כל אחת מספקת יכולות שונות מחברתה. כאשר לפני גרסה 2, היא החזיקה רק תוכנה אחת בשם gbak.

התוכנה מאפשרת לבצע "גיבוי חם" – כלומר גיבוי בזמן העבודה על מסד הנתונים ללא גרימת נזק כלשהו. אבל זה לא החלק המעניין באמת בנושא.

יש לה הרבה יכולות כדוגמת:

  • המרה בין סביבה לסביבה (למשל Little/Big Endian,‏ 32 מול 64 ביט וכו)
  • דחיסת מידע וניקוי המידע שנשמר ממחיקות (למשל)
  • שינוי פעולות אבטחה, כדוגמת שינוי משתמש ו/או סיסמה למסד הנתונים
  • גיבוי למספר קבצים קטנים את המידע של מסד הנתונים
  • שדרוג בין גרסאות של השרת, ובכך להמיר דברים לפי הצורך

ועוד פעולות נוספות, כדוגמת שחזור אותו המידע 🙂

כמו כן, אין הגבלה בביצוע הגיבויים למיקום של מסד הנתונים, כלומר ניתן להתחבר למסד נתונים שממוקם במקום אחר ולבצע את הגיבוי אצלך על המחשב.

לאחרונה נכתב פוסט המתאר כי שימוש במילים stdin ו stdout מפורשות מילולית, וכתיבתן אינה מתייחסת להתקנים עצמם הקיימים במערכות יוניקס שונות. הסיבה לכך מסתבר, היא שהפעולות שgbak זקוק להן, אינן נתמכות בהתקנים האלו, כדוגמת ביצוע seek על מידע, ולכן כאשר הפקודה רואה את המילים הללו, היא מבינה כי היא צריכה לזרוק פלט למסך או לקרוא קלט ממנו, כלומר התוכנה מתייחסת למילים אלו בצורה מפורשת.

העניין הוא, שFirebird מסוגל לרוץ גם במערכות כדוגמת Windows, בהם אין התקנים כאלו בכלל, אבל עדיין הפקודה תומכת במילים הללו, אשר כאמור מפורשות מילולית.

עוד קצת מידע בנושא מתעוד רשמי של הפקודה.

IPC באמצעות Redis ורובי

Redis הוא מסד נתונים אשר אינו מבוסס SQL וכתבתי עליו רבות כאן בעבר.

לאחרונה נדרשתי לפרק מערכת שלי למספר תתי מערכות, ולהעביר מידע בניהם. כמובן שיש הרבה מאוד דרכים לעשות זאת, כדוגמת Message Queue ‏(RabitMQ, ZeroMQ וכו'), עבודה עם PIPES ביוניקס, עבודה בתצורת client server ועוד הרבה מאוד דרכים כיד הדמיון והמערכת הטובה לכם. אני החלטתי ללכת על Redis.

הסיבה לכך פשוטה: אני צריך לבצע פעולה, ואחרי שתפסתי את האירוע, המידע לא צריך להישמר בזיכרון. יותר מזה, אם וכאשר יש הפסקת חשמל, אתחול או אפילו איבוד מידע, אזי אין לי צורך לבצע שוב את הפעולה. כלומר היא נכונה רק לשלב שבו היא נשלחה.

דבר נוסף, הוא שהמערכות שלי כתובות ברובי, ורק מה שצריך לקבל כאירוע לא נכתב, וRedis גם ככה כבר מותקן, ואני כבר מכיר אותו, ויש לי מעט מאוד זמן לכתוב את השינויים.

לRedis יש מספר דרכים לשלוח ולקבל אירועים, אבל אני הולך לדבר כאן על Publish ו PSubscribe. האחרון מאפשר להאזין להודעות באמצעות תבנית חיפוש (עם כוכביות), במקום שם מלא ומדוייק שאחיו Subscribe מספק.

לשם כך צריך לפחות 2 פרוססים שונים, האחד שולח הודעות, והשני מקבל.

שליחת הודעות מאוד פשוטה:

require 'rubygems'
require 'redis'

redis = Redis.new(:host => 'localhost')

10.times do |i|
  redis.publish("number_#{i + 1}", Marshal.dump({:number => i}))
  sleep( (i + 1) / 10.0)
end

התחברתי לRedis, והתחלתי לרוץ על כל המספרים מ0 ועד 9.
יצרתי מפתח שההתחלה שלו הוא number_‎ ולאחר מכן המספר. המבנה חשוב מאוד בשביל להצליח להאזין לאירוע.
לאחר מכן, יצרתי תצורה בינארית עבור Ruby Hash ושלחתי אותה כמידע שאני זקוק לו לשימוש.
כאשר הפעולה מסתיימת, אני נח כמות של מילישניות לפי המספר, החישוב לדעתי די ברור כאן.

הפרוסס השני צריך להקשיב לאירוע:

require 'rubygems'
require 'redis
redis = Redis.new(:host => 'localhost')

redis.psubscribe('number_*') do |on|
  on.pmessage do |pattern, event, message|
    puts "pattern: #{pattern}, event: #{event}, message: #{Marshal.load(message)}"
  end
end

כאן אנחנו מקשיבים לפעולות אשר נשלחות עם סוגי publish השונים.
יש האזנה לאירועים באמצעות תבנית (pattern) ומכאן המקדם בעצם של הפקודה (p).
הפקודה בעצם מכניסה אותנו לתוך בלוק אשר דרכו אפשר להאזין למגוון סוגים של אירועים.
כן האירוע שצריך הוא pmessage לו אני מאזין, וכאשר הוא מתרחש, הקוד בתוכו מורץ.
אני משחזר כאן את המידע הבינארי חזרה למחלקות של רובי, ובכך העברתי מידע סיריאלי לחלוטין של רובי.
חשוב להבין כי זוהי פעולה שהיא blocking, ולכן כאשר מריצים אותה, אין המשך כלפי מטה לקוד.

התוצר כאן יהיה בסגנון הבא:

pattern: number_*, event: number_1, message: {:number=>0}
pattern: number_*, event: number_2, message: {:number=>1}
pattern: number_*, event: number_3, message: {:number=>2}
pattern: number_*, event: number_4, message: {:number=>3}
pattern: number_*, event: number_5, message: {:number=>4}
pattern: number_*, event: number_6, message: {:number=>5}
pattern: number_*, event: number_7, message: {:number=>6}
pattern: number_*, event: number_8, message: {:number=>7}
pattern: number_*, event: number_9, message: {:number=>8}
pattern: number_*, event: number_10, message: {:number=>9}

ה gem הראשון שלי

באוגוסט 2012 כתבתי על ספרייה שאני עובד בשם redis_session. משום מה, התגובה היחידה שקיבלתי בפרטי, היתה כי אין לי מספיק בדיקות (ולא על כך שהיא לא מתועדת למשל).

לאחרונה חזרתי אליה, ושיפצרתי אותה יותר, ואף יצרתי לה מערכת בדיקות אוטומטיות עם rspec ואפילו הוספתי תעוד של rdoc (שוקל להמיר ל yard), ובין חמישי לשישי פרסמתי את ה gem שלי לראשונה להורדה באמצעות מנהל החבילות של רובי.

אני חייב לציין שזה היה פשוט מידי לעשות את המהלך. הרשמה לrubygems, הורדת ה gemcutter מרובי gem, יצירת ה gem ואז ביצוע push עם הדוא"ל והסיסמה של rubygems וזהו 🙂

אני יודע שסטטיסטיקה חשובה לכם, אז נכון לכתיבת הפוסט היו 40 הורדות של ה gem פחות מ24 שעות לאחר הפרסום שלו, שלדעתי לפחות זה מדהים 🙂

מלח הארץ

לאחרונה אני מוצא צורך לממש דברים בעצמי במקומות שהייתי מצפה שיהיה מימוש קיים לדברים שאני צריך. אז לפני שאני כותב משהו, אני מעדיף לחקור דברים לעומק, ולהבין כיצד הם בעצם עובדים.
למשל אני זקוק למערכת ניהול משתמשים וסיסמאות, וכל מה שמצאתי עבור מה שאני עובד בו, כתוב בצורה שלדעתי לפחות, לא מספיק מאובטחת, אז החלטתי לכתוב אחד בעצמי. זה לא כזה מסובך, או הרבה עבודה (מסתבר).

כאשר שומרים פרטים של משתמש וסיסמה, חשוב לא לשמור את הסיסמה עצמה, אלא חתימה חד חד ערכית שלה.
הסיבה לכך מאוד פשוטה: אם בטעות מישהו מצליח לגשת למסד הנתונים, הוא לא ידע מה הסיסמה של המשתמשים שלך, ובכך לפחות עמודת הסיסמאות אינה שימושית בצורה ה"רגילה" שלה.
בשביל שהיא כן תהיה שימושית, צריך בעצם ליצור סוג של מילון שמתרגם hash למה שהרכיב אותו.

בשביל להפריע לתרגום של ה hash שהוא חייב להיות ייחודי לאוסף הבתים של הסיסמה, המציאו דרך של תוספת. התוספת הזו נקראת Salt. היא בעצם "ממליחה" את חתימת הסיסמה עם עוד תוספת שייחודית פר יצירת סיסמה (ואסור לה לחזור שוב פעם במסד הנתונים בשביל שתהיה מספיק בטוחה). הסיבה היא, שבמידה ויש יותר ממשתמש אחד עם אותה הסיסמה, עדיין החתימה תהיה ייחודית, ובכך גם אם "גיליתי" את הסיסמה של משתמש אחד באמצעות "תקיפה" של hash, עדיין זה לא יהיה רלוונטי לשאר הסיסמאות שחוזרות על עצמן.

השימוש בSalt אומר כי החתימה היא בעצם הSalt פלוס הסיסמה (או הסיסמה פלוס ה Salt). יש עוד הרבה דרכים לעשות את זה, כדוגמת הוספת ביטים/בתים לסוג הhash וכו' כאשר משתמשים בSalt, אבל העיקרון בסופו של דבר אומר, כי החתימה של הסיסמה זה Salt וסיסמה בייחד, ולא רק הסיסמה לבד.

כאשר "חותמים", כיום מומלץ בחום לא לעבוד יותר עם md5, היות ויש לו התנגשויות. כלומר ישנה יותר מסדרת בתים אחת שיכולה להיות עם אותה חתימה. אז אני משתמש ב sha256 במקום. הנה קוד רובי המדגים כיצד יש לבצע זאת: להמשיך לקרוא

מידע, כריית מידע ואתם

לאחרונה שוב פעם שמתי לב למשהו מעניין בlinkedin. הוא מציע לי אנשים שאני מכיר, אשר עם כולם דיברתי בדוא"ל כזה או אחר, אבל מעולם לא פניתי אליהם באתר. מצד שני, מעולם לא נתתי לאתר לסרוק את תיבת הדואר שלי. אז איך הוא לעזאזל "יודע" שאני מכיר אותם ?

למשל בחורה שיצאתי איתה מספר שבועות (וגם התכתבנו בין היתר בדוא"ל), פתאום הופיעה לי ב linkedin. אפילו לא ידעתי שהיא שם, שלא לדבר על כך שזה די מוזר איך הוא בכלל יודע את זה שאנחנו מכירים.

ובכן, יש עולם שנקרא כריית מידע. מערכת שזוכרת הכל ומצליבה הרבה מאוד נתונים מהרבה מאוד מקורות, וכאשר X וT מתאימים, אז גם X וגם T פתאום צצים להם בייחד. כבר הזכרתי את הנושא מספר פעמים אצלי בבלוג בעבר.

מספיק שיש לlinkedin מידע על כתובת הדוא"ל שלי, ולסרוק דוא"ל של אדם אחר, בשביל לדעת להצליב את המידע הזה של "רגע הם מכירים איכשהו וממשהו, אציג להם אחד את השני". גם אם אי פעם חיפשת את האדם, ואכישהו היא חיפש אותך, גם זה נכנס כמידע. גם אם הוא הגיב באיזה קישור שאתה הגבת בו, זה נרשם. למעשה כל הפעילות שלך נרשמת.

עכשיו נגיד וזה הכל (כמובן שזה לא). העניין הוא שהרבה מאוד חברות סוחרות במידע עלינו, ומרוויחות הרבה מאוד כסף על כך. כלומר המידע שאנחנו מספקים להם, נמכר הלאה. זה נקרא leads. נגיד חיפשנו פעם מתכנת, אז נרשמנו באיזשהו מאגר, והמידע הזה עכשיו יסחר לפחות פעם אחת הלאה.

וכאן צריכה להישאל שאלה גם משפטית ובעיקר אתית: מה ואיך להגן על עצמנו מכריית מידע, האם זה בכלל אפשרי, וכיצד יש לנהוג עם מידע בכלל.

יצירת מסד נתונים בזמן ריצה

אחת הפעולות המעצבנות ביותר שאני מגלה בהתקנות בלינוקס, היא שאין יצירה של מסדי נתונים בקוד, אלא דורשים ממני ליצור בעצמי את מסד הנתונים בשביל להתחיל לעבוד עם התוכנה.

אז החלטתי להציג כמה קל ופשוט כאשר עובדים בכלים הנכונים ליצור מסדי נתונים בקוד עצמו. החלטתי להשתמש ב Firebird SQL, סתם כי אני יכול 🙂

createdb

אם אתם עוקבים אחרי הבלוג שלי, אתם יודעים כבר כי המסך הזה נוצר באמצעות לזרוס, ומדובר בסה"כ בLabel ו Edit , עם קינוח של Button.
בנוסף זרקתי רכיב לא וויזואלי של TIBConnection, שמטפל לנו בחיבור למסד נתונים מבוסס Firebird.

אשאיר לכם להשקיע 2 דקות מזמנכם לטפל במראה המתאים לכם.

לאחר מכן, באירוע של הכפתור, אצור את הקוד הבא:

procedure TfrmDBCreate.btnCreateClick(Sender: TObject);
var Transaction : TSQLTransaction;
begin
  FBConnection.DatabaseName := edtDatabaseName.Text;
  FBConnection.CharSet      := 'UTF8';
  FBConnection.HostName     := edtHost.Text;
  FBConnection.UserName     := edtUserName.Text;
  FBConnection.Password     := edtPassword.Text;
  Transaction               := TSQLTransaction.Create(nil);
  FBConnection.Transaction  := Transaction;
  try
   FBConnection.CreateDB;
   FBConnection.ExecuteDirect('CREATE table test1 (name varchar(24) not null)');
   Transaction.Commit;
   MessageDlg('Info', 'The database was created.', mtInformation,
             [mbClose], -1);
  except
    on e : EIBDatabaseError do
     begin
       MessageDlg('Error', 'Could not create database : ' + LineEnding +
                  e.Message, mtError, [mbClose], -1);
     end;

     on e : Exception do
       begin
        MessageDlg('Error', 'Unknown error : ' + LineEnding + e.Message,
                 mtError, [mbClose], -1);
       end;
  end;
  Transaction.Free;
end;

קודם כל אנחנו מזינים לTIBConnection את הפרמטרים שהוזנו, כדוגמת קובץ מסד הנתונים, הכתובת של השרת, בנוסף החלטתי להשתמש ב UTF8 כקידוד למחרוזות.
בנוסף יצרתי רכיב עבור טרנזאקציות, הוא צריך להיות בשימוש לשאילתא שאריץ לאחר יצירת מסד הנתונים (כל השימוש בו).
בתוך try אני אומר למנהל החיבור למסד נתונים ליצור את מסד הנתונים. חשוב לדעת כי זה קיים בכל החיבורים שלנו למסדי נתונים המבוססים DataSet, ולא ייחודי ל Firebird.
לאחר מכן, החלטתי גם להציג כיצד ניתן ליצור בתוך אותו קוד טבלה, אז יצרתי טבלה בשם test1 עם שדה בשם name שהוא מסוג varchar ומסוגל לקבל עד 24 תווים.
נעשה על השאילת commit, ואנחנו מוכנים !

במידה ויש חריגה בעת הריצה, אז אם מדובר בחריגה של מסדי הנתונים, נציג על כך הודעה מיוחדת, אחרת, נציג הודעה כללית על השגיאה שהתקבלה.
בסוף אני משחרר את הטרנזאקציה, וזהו, זה כל הקוד שצריך.

מי אמר שעבודה עם מסדי נתונים צריכה להיות כואבת ?

את קוד המקור תוכלו למצוא כאן
 

תובנות השוק מהרצאה שהעברתי

העברתי ללקוח אשר חי ונושם "מיקרוסופט" הרצאה על טכנולוגיות שהוא אינו מכיר, אבל יכולים לשנות לו את כל מאזן ההתמודדות שלו עם דברים שקיימים כיום בשוק.

ההרצאה היתה על git וההבדלים בינו לבין svn. היות והוא הגיע למצב בו מפתחים כל הזמן דורכים אחד על השני, ורציתי להציג להם דרך אחרת או אולי נוספת לעבוד, לא במקום svn, אלא בנוסף (תודה לסוייר על המצגת שהוא יצר בזמנו בנושא, והסכים לתת לי אותה).

לאחר מכן, העברתי הרצאה על No(t only) SQL. בהרצאה העברתי הסבר מה זה בגדול אומר, איך מבינים בכלל מתי, ואיך הוא מתאים לנושא, התמקדתי בMongoDB ובRedis. שני מסדי נתונים אשר אני משתמש בהם.

הדגמתי להם לפי צורות העבודה שלהם, כיצד הם יכולים לשפר להם את הביצועים, למנוע בעיות עומסים שונים וכו'

בסוף ההרצאה ניגש אלי אחד העובדים – מפתח #C, ומתכנת באמת מוכשר, ואומר שזה הכל נחמד ויפה, והכרתי לו הרבה דברים חדשים, אבל אם אין הכשרות של זה בשוק (הישראלי), אין סיבה להשתמש בטכנולוגיות האלו.

ניסיתי להסביר לו כי העולם הטכנולוגי, מחוץ לעולם המיקרוסופט, הוא עולם מאוד דינאמי אשר משתנה מהר מידי בשביל באמת להצליח ללמד אותך משהו במכללה. לפחות משהו אשר יהיה נכון גם שנה לאחר מכן, ולכן נהוג לקרוא מידע ולחקור לבד – וזו פעולה שכבעל מקצוע מאוד נחוצה. בנוסף גם הזכרתי לו כי התפקיד של מתכנת זה לא להיות code monkey ורק לכתוב קוד כל היום, אלא תפקיד של המתכנת  הוא לספק מענה לצרכים שונים, והדרך לכך היא להכיר כמה שיותר כלים, וצורות עבודה.

אפילו הסברתי לו כי לא בכדי מרבית התעשייה אינה עובדת בתפיסת העולם של מיקרוסופט, אלא גישה דינאמית וכלים לגמרי שונים. ויותר מזה, כל עולם ה "cloud", אינו זהה אחד לשני, אלא לכל ארגון יש דרישות שונות והדרישות האלו משתנות מידי בשביל לבחור בתבנית הקבועה.

לאחר השיחה הבנתי (שוב) – רוב האנשים והשוק אינם מסוגלים לראות מעבר לכאן ועכשיו. הם לא מסוגלים לדמיין כי דרכי העובדה שלהם צריכים להשתנות כאשר הם אינם מקבלים מענה נכון, היא פעולה מאוד חשובה, אך אם אנשי המקצוע אינם מכירים עוד כלים, הארגון תמיד יהיה תקוע באותו המקום עם אותן הבעיות.

או כפי שאברהם מאסלו אמר פעם – כאשר יש בידך פטיש, הכל נראה לך מסמר
אתה פשוט לא מסוגל להבין כי לפעמים יש שימוש גם למברג, שפכטל וכו' …

Redis Session for Ruby

I'ved created a standalone session system based on Redis database.
This session system was not build only for web in mind, but also for non web based systems.
I for example, use it with Asterisk based programs that I'm writing to clients.

The session lib supports at the moment only few features:

  1. Connect to Unix sockets
  2. Connect to TCP sockets, and changing the port number if needed
  3. Expiring all keys
  4. Expiring specific keys
  5. Changing expiry of a specific key
  6. Checking expiry of a specific key
  7. Saving and restoring Ruby based structures such as hashes, arrays, boolean etc…
  8. Removing keys
  9. Prefix that will be automatically added to each key name (in saving and restoring)

The usage of the system is very simple:

require 'rubygems'
require 'redis_session'
session = Session::SessionClient.new(:prefix => 'add_test') # init the session
session.save('name', { 'name' => 'session'}) # Saving a content. Pure ruby content
restored = session.restore('name') # return to me a pure ruby content
puts restored.inspect
session.remove('name') # delete the key
view raw sessoin.rb hosted with ❤ by GitHub

The current version (0.1.3), does not contain yet any documentation. However it will be added in next version.
The library itself is under the MIT license, and can be downloaded here.

You can create your own gem file. I hope that by the next version, it will be created automatically.

* You must have active Javascript support for wordpress.com and github to view the source code.

Redis – From client to execution

העברתי בפרל מונגרס הרצאה על לקוח הרדיס שאני יוצר.

שעה לפני התחלת ההרצאה, קיבלתי בדיוק דוא"ל מבחור מיוון שהודה לי מקרב לב על הלקוח שעוזר לו מאוד. שזה בפני עצמו היה ממש כיף לקבל.

את ההרצאה לא תוכלו לקבל ברשת, אבל את השקפים המטורפים שלי כן:

CentOS Packages

I find myself once in a while with a need for software package that does not exists for CentOS (or at least not the version I need them to be), so I find myself maintaining some spec files (and sometimes even more) of the required software.

I started adding such packages to GitHub, in order also to help others if they also find themselves with such a need.

At the moment I have 2 packages:

In the feature I might add additional packages, and also merge them into one big tree

You are more then welcome to fork me at Github 🙂

חבילות ל CentOS

אני מוצא את עצמי מידי פעם זקוק לחבילה של תוכנה כזו או אחרת אשר אינה קיימת בCentOS (או לפחות לא בגרסה שאני צריך). לכן מידי פעם אני מוצא את עצמי מתחזק קובץ spec ולפעמים קצת יותר, של אותה תוכנה.

התחלתי לשים חבילות כאלו בgithub אצלי, במטרה גם לעזור לאחרים לקבל מענה הולם במידת הצורך.

כרגע יש 2 חבילות:

בעתיד אוסיף עוד חבילות במידת הצורך, ואולי אמזג את זה לעץ אחד.

כרגע אתם מוזמנים כמובן לעשות לי Fork בGitHub 🙂

מבוסס על רעיון אמיתי – פרק ראשון – חלק א'

חלק א'

הוא נכנס לחדר מהמעלית. מיד ראיתי כי הוא חסר ביטחון, ולכן החלטתי לעשות את הפניה הרגילה שלי לכל אותם אלו המגיעים לכאן בפעם הראשונה:
"אתה צופה באח הגדול ?" שאלתי בגיחוח קל לעבר ה"קורבן" החדש, במקום להציג את עצמי כמקובל בחברה.
הוא ענה: "ברור, כמו כולם".
ניסיתי להשחיל אותו למחילת הארנב, ושאלתי: "ו… אתה נהנה מזה ?"
הוא ענה "זה כבר לא מה שהיה פעם, פעם זה היה מלהיב יותר, היום סתם מנסים ליצור כותרות".

הצלחתי ! הוא שלי ! נכנס למלכודת, אפילו לא הייתי צריך להתאמץ. להמשיך לקרוא

My roadmap for open source projects

All work and no play, makes IK a bad open source dev.

Recently I was required to stop the work on my Redis client due to lack of time. But I still going to finish the client, but it will take more time then what I thought it would.

But it made me think, what exactly are the things I wish to develop and contribute for open source projects.

So after the Redis client work, I wish to work on the following projects (some will be mine):

  • Contributing to Adhearsion
  • Creating web framework to fpWeb (It's just a CGI framework, not a whole web framework)
  • Working on a library I wanted to start in 2010 for VoIP
  • Continue working on Redis client when needed

I have no time frame limit for this, but that's the open source stuff I wish to work on when I'll have more time.

fpIndexer

fpIndexer הוא מנוע קוד פתוח הנועד לסרוק טקסט וליצור עבורו אינדקסים אשר יעזרו לחפש טוב יותר את המילים השונות, ואף ליצור מעל התוצר שלו במסדי נתונים, גם מנוע מסוג Full Text Search

המערכת מכילה 2 סוגי כלים, הראשון הוא מאנדקס – הכלי אשר יוצר בעצם את האינדקסים של המילים השונות. והשני הוא כלי החיפוש.

המאנדקס והמחפש בנויים בצורה מודולרית ומכילים את המחלקות הבאות:

  • מחלקה עבור שמירה ושליפת מידע
  • מחלקה עבור אינדקסים
  • מחלקה לחיפוש
  • מחלקה לעיבוד טקסט

מה שקורה הוא, שהמאנדקס משתמש במחלקת "עיבוד טקסט ושמירת המידע" עבור יצירת מסד נתונים לחיפוש.
המחלקה לחיפוש משתמשת גם היא "במחלקת שמירה ושליפת המידע" עבור חיפוש במסד הנתונים.

בזמן כתיבת הפוסט, ישנה תמיכה בארבעה צורות של "שמירה ושליפה של המידע":

  • מסד נתונים בזיכרון
  • קובץ שטוח
  • Firebird SQL
  • SQLight

המערכת יודעת לסרוק כרגע שלושה סוגים של מבני קבצים:

  • קבצי טקסט רגילים (plaintext)
  • קבצי HTML
  • קבצי Pas

המפרש נבחר לפי סיומת הקובץ, במידה וסורקים קבצים, ולא stream המכיל מילים.
יש תמיכה ברשימת מילים אשר רוצים להתעלם מהם (פר שפה) – כלומר blacklist, הכוללת תמיכה בהגדרת מסכה של מילים להתעלמות, ולא רק תמיכה במילים שלמות.

מעל מאנדקס הטקסט/stream, קיים גם מימוש של אינדקס השייך למסד הנתונים, דבר המאפשר ליצור מנוע full text search מעל מסד הנתונים.

המערכת מגיעה עם מספר תוכנות הדגמה של השימוש.
עוד פרטים ניתן למצוא בקובץ ה readme.

האם Framework צריך להתערב בגישות אבטחה ?

במהלך השבוע התפרסם מקרה בו Rails – ‏ framework בשפת רובי, מכיל בעיית אבטחה אשר מאפשרת לבצע סוג של הזרקת תוכן למידע שאסור לערוך אותו. למשל לפתוח מחדש דיווחי באגים ב GitHub (כפי שמגלה הבעיה הדגים, כולל שינוי תאריכים לעתיד).

לאחר קריאה יותר מעמיקה, הסתבר כי הבעיה היא לא ב Rails, אלא בחוסר שימוש ביכולות שיש לו, או חוסר שימוש נבון בהם, אשר גורמים לבעיה.

הבעיה הזו הולידה הוויכוח, אשר הציג כי בעיית האבטחה וחוסר החלטה להפעיל את ההגנות בברירת המחדל, מאוד שונה מהרעיון שבו Rails בנוי, והשאלה היא כיצד יש לפעול.

Rails מאוד שונה בגישה שלו מהרבה frameworks, בכך שהיא מגיעה בפילוסופיה האומרת כי הוא מכריח אותך לעבוד בגישה שלו:

Rails is opinionated software. It makes the assumption that there is a “best” way to do things, and it’s designed to encourage that way – and in some cases to discourage alternatives. If you learn “The Rails Way” you’ll probably discover a tremendous increase in productivity. If you persist in bringing old habits from other languages to your Rails development, and trying to use patterns you learned elsewhere, you may have a less happy experience.

כלומר  עלייך לעבוד בגישה שלו, או בכלל לא לעבוד איתו, אחרת לא תסתדר במיוחד.

כך שאנו זקוקים לשאול את השאלה: כיצד Rails צריך להתנהג בנושא ?

האם עליו להכתיב את הדרך להגן על שדות ?

או האם מתכנתים צריכים לדאוג לנושא בכל פעם מחדש (למשל Rails מוסיף לכל טבלה 2 שדות בעצמו, אבל לא מגן עליהם, למרות שברירת מחדל הוא מנהל אותן) ?

למרות שעל פניו זה נשמע ממש פשוט, זה לא באמת כזה פשוט להחליט. מה הכיוון שרוצים לקבל ? האם כל תוכנה צריכה לקבוע כיצד אבטחת המידע בה תתבצע, או האם ה framework צריך לקבוע קו ?

ומה אם הקו הזה מתנגש עם האפליקציה ? הרי הframework אמור להיות כלי שעוזר לי ליצור אפליקציות, לא האפליקציה. אני צריך לדעת להשתמש בו לצרכים שלי, ולא לגרום לצרכים שלי להיות מותאמים לחשיבה שבה  ה framework מנסה לעבוד. כלומר במידה והצרכים שלי אינם מתאימים ל framework, אז הוא לא מתאים למה שאני צריך לעשות. בייחוד בכלי כדוגמת Rails.

התגובה של מפתחי Rails היא שהאבטחה צריכה להגיע מהמתכנתים עצמם. הדעה שלי קצת חלוקה בעניין.

מה אתם חושבים ?

Yes SQL, No SQL

Freedom-of-choiceUnlike the attempt to picture things, the idea of non SQL based databases exists for many years.

The thing is, that sure SQL based databases are important, but they are not the only means to use. You need to better understand your needs before you choose the proper way to store and retrieve data.  "NoSQL" is not the answer for life, universe and everything (that's 42), but it's another way to look at your data.

It's not always possible to use the same structure to handle data. Sometimes your data structure is way too simple to use SQL, Sometimes it's too complicated for SQL to handle, and sometimes, it just does not matter.

The idea is to understand the way you require to handle data. For each type of requirement, there is a different penalty that you'll have to pay, in order to have what you wish for. There is no magic, no voodoo or anything else, for every solution. There is a penalty at some point, in order to provide you the answer for the requirements you surfaced.

SQL based databases are usually more reliable way to store data, but they are slower in  many ways.

The New types of "NoSQL", are suited for the buzz world of "cloud computing" (aka grid computing), databasebut they return fast with "good" answer, even when something went wrong. The thing you must understand is that they usually queue your request, and handle it later on. It makes you work fast, but you must be less reliable on your data, until you can validate it. It's good when you need to provide multiple requests per seconds, but as you can understand, that's a big price to pay.

The Old style of "SQL", is usually more ACID based. Each action is validated when it executed, and returned to you. It's slower but more reliable with it's answer.

There are in-between databases as well. There are "NoSQL" based databases that are full ACID, and return with the proper answer, and "SQL" databases that are not full ACID and return valid answer that might not be valid when it actually executed.

The thing is, that you must understand and know what, when, and where to choose. The boundaries are not so easy to set on many cases. If you have to provide the user a lot of information, then that's one path to take. But if you have a lot of write and updates, that's another path you should choose

The design of your data, and the way you work, also have effect on how to choose your tool.

So instead of ignoring hypes or joining them, remember, that "Yes SQL" and "No SQL" are two different sides of the same coin. And sometimes you must choose both of them for the same project.

resources

Timeout records – Feature request

Foreword

For several years now, I'm yearning for a feature that I think that all SQL based databases that I know are missing, and throw it back to the program side.

The feature I wish to have is a way to set a specific record to be valid for only a known period of time, and when the time is up, I'll be able to do something.

In this post I'll try to create some sort of general specification for such feature, and I hope that there will be many comments on this that will benefit everyone, and I hopeful, that they will make the idea better.

The Idea

An SQL statement that allow me to create, update and cancel a set of timeout per record or a where statement. It can look like this.

A record that is pointing to such timeout, can not be entered to another timeout rule. Any attempt to add additional timeoutout rule to such record must raise and exception, even if it part of a "where" statement, so the statement will have to have condition to exclude it from the new rules.

A Create new timeout condition can look something like this:

CREATE TIMEOUT <timeout name> FOR <table name> SET <time in seconds | TIMESTAMP timest> <IDENTIFIED BY id | WHERE condition> [ON TIMEOUT TRIGGER <trigger name>]

An Update condtion for existed timeout can look something like this:

UPDATE TIMEOUT <timeout name> FOR <table name> SET <time in seconds | TIMESTAMP timest> <IDENTIFIED BY id | WHERE condition> [ON TIMEOUT TRIGGER <trigger name>]

And a removing of a timeout can look something like this:

DROP TIMEOUT <timeout name>

Looking up for the time left for a record:

SELECT <timeout name [,timeout name ...] | *> FROM <TTL> [where condition]

Where TTL is a place that the query can get this information.

More details

The idea is to be able to raise a trigger when the time is out, but if no trigger was set, then the record or records are removed. If the database have audit-trail (Firebird SQL for example), such trigger-less timeouts will be marked there.

Beside the creation, editing and deletion of the rule, there should be a way to see how much time was left for a specific rule, or set of rules.

If something went wrong, then an exception should be raised.

That's the whole idea in general. I'll be more then happy to hear what you have to say about it.

המפרש החדש שכתבתי ל Redis

בפרק הקודם סיפרתי על הקרב שלי עם Redis. בעקבותיו, שכתבתי את המפרש של Redis לגמרי מהיסוד. יש דברים שהעתקתי מהגרסה הקודמת כי עבדו טוב, אבל שיניתי איך הדברים מתבצעים בפועל גם בקוד הישן.

בכל הנושא הזה, היה לי באג אחד אשר לקח לי יום אחד למצוא אותו, היות והוא התרחש רק במקרים מאוד ספציפיים. בהתחלה חשבתי כי אולי ה mock שאני משתמש בו לא תקין, אז ניסיתי לכתוב אחד בעצמי (במקום הקוד שבמקור לקחתי מwireshark), וגיליתי שהמפרש שלי מצויין אפילו, כי הוא הרים לי מייד חריגה על כך שהמבנה לא תקין (מה שרציתי לבדוק). זו לא חריגה של משהו שלא ניהלתי טוב, אלא זו חריגה אשר התרחשה מהקוד שלי,  אשר נכתב בשביל להעלות במידה ומשהו במבנה לא תקין.

אז התחלתי לשגע את כל העולם ואחותו ברעיונות איך לדבג את הבאג שיש לי, היות ולא הצלחתי למצוא מה הגורם שלו. ובשביל זה צריך בעצם להסביר את הגישה השונה שיצרתי למפרש, ולמה בעצם כל כך קשה לדבג את הקוד. חשוב להדגיש כי הבעיה היא לא לסרוק בתים, אלא להחליט מה שייך למה, מתי ולמה, ולדעת להתאים את עצמך לדרישות. כלומר לרוץ בצורה לינארית משמאל לימין על buffer מעולם לא יצר שום בעיה במימוש (קשור לדיון שהיה לי בנושא), אלא לעשות את זה בצורה קלה, מהירה, ונוחה, זו כבר משימה יותר מורכבת.

אז איך הרעיון של המפרש החדש בנוי, אתם בטח שואלים ? להמשיך לקרוא

באג מעניין בFirebird

ביום שישי חברה המספקת שירותים למספר בנקים ומשרדים ממשלתיים ברוסיה, דיווחה על קריסה מאוד מעניינת של Firebird בשרת שלהם.

יש להם שרת בנראה ככה בשעות שנחשבות ל idle:

top - 03:20:39 up 10 days,  8:39,  7 users,  load average: 2.08, 1.87, 2.15
Tasks: 1732 total,   1 running, 1730 sleeping,   1 stopped,   0 zombie
Cpu(s): 11.9%us,  4.0%sy,  0.0%ni, 83.5%id,  0.0%wa,  0.0%hi,  0.6%si,  0.0%st
Mem:  529177288k total, 378587600k used, 150589688k free,   761532k buffers
Swap: 1073741816k total,   130612k used, 1073611204k free, 333281232k cached

   PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
15840 t-mvv     20   0 33.3g 9.1g  25m S 209.9  1.8 932:23.24 java
15931 root      20   0  578m 226m 165m S 75.3  0.0 286:12.21 rdb_inet_server
16101 root      20   0  486m 198m 164m S 41.4  0.0  60:34.22 rdb_inet_server
15897 root      20   0  956m 509m 166m S 21.5  0.1 126:36.86 rdb_inet_server
46960 qemu      20   0 1365m 1.0g 2156 S  5.2  0.2 973:33.28 qemu-kvm
61680 qemu      20   0 1366m 1.0g 2536 S  4.6  0.2 934:21.36 qemu-kvm
24615 root      20   0  466m 112m  96m S  3.6  0.0   0:08.07 rdb_inet_server
...

[root <at> mvv bin]# ps aux | grep -c rdb_inet_server
719

Database is on a small FusionIO drive:

mount:
/dev/fiob on /mnt/db type ext2 (rw,noatime)

df -h:
/dev/fiob             587G  423G  135G  76% /mnt/db

ls -l:
-rw-rw---- 1 root root 453031493632 Feb 11 03:26 ncore-mvv.fdb

מסתבר שכאשר שרת מסד הנתונים מגיע להגבלה של 2 גיגה לנעילה (הגבלה של מערכת ההפעלה עד כמה שאני מבין) הוא קורס.
עכשיו בשביל להסביר לכם את הנתונים קצת יותר, בשעות ה idle היו כ 2,500 חיבורים פעילים למסד הנתונים שבצעו פעולות.

להמשך קריאה ואולי אף מעקב בעתיד.

Redis סיבוב שלישי

הסיבוב הבא עם Redis הולך להכריע איך יגמר הקרב ביני לבין מסד הנתונים המעצבן הזה.

הצלחתי לגרום למפרש שלי לעבוד עם כל דבר שהפרוטוקול מדבר עליו, ואפילו על מספר דברים שמצאתי שהוא לא מדבר עליו, אבל קיימים. ואז קיבלתי סנוקרת אשר הראתה לי קצת כוכבים. המכה גרמה לי לעצור יומיים ולחשוב איך להתמודד איתה, וב2 בלילה הבנתי מה אני צריך לעשות (ארכימדס, מאחוריך).

הבעיה התחילה כאשר פקודה (slowlog) אשר נוצרה לפני 7-8 חודשים במסד נתונים מחזירה משהו אשר מנוגד לגמרי לכללי הפרוטוקול של המסד. כלומר היא מחזירה ערך במבנה חוקי, אבל הפרוטוקול אינו מדבר על הדרך הזו שבכלל נתמכת. ואז בתעוד הפקודה עצמה (לא של הפרוטוקול) אני מוצא משפט קטן ומעצבן שנכתב על השימוש בתכנת ה cli של המסד עצמו: להמשיך לקרוא

Redis סיבוב שני

אומרים הרבה פעמים לא לבדוק את שיני הסוס, במידה והוא מוכשר. אני לא מסכים עם האמירה הזו. היות והיא לרוב שגויה. סוס שלא מסוגל לאכול כמו שצריך, לא משנה כמה הוא מוכשר, לא יהיה סוס מרוץ/מלחמה טוב, אם להמשיך את המטפורה הזו (וסליחה אם זה פוגע במישהו, זו לא הכוונה).

עברתי בRedis משלב כתיבת הפרוטוקול, לשלב יצירת הפונקציות השונות. ואם בכתיבת הפרוטוקול היו לי חששות כבדים, אז לצערי הם הרבה יותר ממתממשים. לא רק שהתעוד לפעמים לוקה בחסר. הוא הרבה פעמים לא נכון. כלומר מה שקורה בפועל ומה שכתוב בתעוד אם הוא כבר כתוב, ובכן, לא תמיד הוא נכון. יותר מזה, יש פקודות אשר אפשר לשחק איתן בדף התעוד, אז הן לא תמיד מגיבות זהה לredis עצמו בפועל.

אני מוצא את עצמי משקיע המון אנרגיה בלעשות סוג של reverse engineering למסד הנתונים הזה, מאשר ליצור משהו. יש פקודות שלוקחות כל כך הרבה אנרגיה סתם בגלל תעוד שגוי.

ניסיתי לפנות לפני שבועיים למפתח של Redis,אבל עד עכשיו לא קיבלתי תשובה. יותר מזה, יש בתעוד הרבה תגובות. חלקן אפילו מצביעות על כשלים בתעוד עצמו, וגם הן לא זוכות למענה.

מצד אחד במימוש שלי, יכולתי לעשות לעצמי חיים קלים הרבה יותר, היות וכתבתי מימוש די אגנוסטי, אשר אם תצפו בקוד, תראו שאין לי משהו מיוחד שנעשה בתוך הקריאה לפקודות וחזרה. כלומר זה די copy paste המימוש הזה. אבל חשוב לי להבין לעומק. יותר מזה, חשוב לי לכתוב תעוד מדוייק במימוש שלי. למעשה אם תקראו את הקוד, אתם תראו שיש הרבה יותר תעוד מאשר קוד בהרבה מקומות. מימוש של שורה אחת לקוד, ו10-15 שורות הסבר על הפקודה עצמה.

ככול שאני נכנס יותר ויותר לקרביים של Redis מבחינת המימוש שלו (לא קראתי את הקוד עצמו), ככה אני פחות ופחות סגור על כך שהוא בכלל שווה נגיעה. אני ממשיך לממש את הפרוטוקול והפקודות שלו, אבל זה כבר לא מרגיש טוב כמו בהתחלה.

Redis or not

טוב זה קצת pun על הצליל, אבל הפוסט הזה עוסק בRedis – עוד מסד נתונים בקוד פתוח שאומר לא לSQL. ואת האמת, הוא לא זקוק לשפה הזו בכלל …

למי שלא מכיר, אז Redis הוא מסד נתונים אשר מספק מערכת Key value עם הרבה יכולות. הוא מאפשר לי ליצור הרבה מעבר ל key value, ולמעשה הוא סוג של data struct manager.

פירוש השם הוא קיצור של מספר מילים ולא כתיבה שגויה של צנון: REmote Dictionary Server. רק אם תהיתם במקרה.

במסד הנתונים הזה, הכל הוא מחרוזת, רשימה של מחרוזות, רשימה מסודרת של רשומות מסוג מחרוזת, או קבוצה של מחרוזות. האורך המקסימלי של כל מחרוזת, יכול להיות עד גיגה בית שלם ! אבל ככול שהאורך גדול יותר, כך היעילות של המידע פוחתת, ולוקחת הרבה יותר משאבים, היות ורוב המידע נמצא בזיכרון, ורק נשמר בדיסק לצורך גיבוי.  העניין הוא שמחרוזת זו מילה מופשטת מידי, היות והמסד יודע לטפל בבתים. כלומר מידע בינארי או מידע טקסטואלי הוא זהה לגמרי עבורו. כך שהוא byte safe.

זה על רגל אחת על מסד הנתונים הזה. להמשיך לקרוא

קבלת רשימה דינאמית של העמודות של כל (חלק) הטבלאות במסד הנתונים

קראתי פוסט ממש מעניין בנושא שכתב אדם בשם Jiří Činčura :

"נשאלתי שאלה לפני שבוע. היא היתה פשוטה מאוד. במידה ואקבל רשימה של עמודות בצורה מסודרת, הייתי רוצה לסרוק את כל הטבלאות (עם מספר תנאים) עבור השמות האלו, ולקבל את התשובה חזרה. זה היה Firebird, אז מייד קפצתי לתוך טבלאות המערכת ויצרתי שאילתא 'on the fly' בתוך execute block, המוכר גם בשם anonymous stored procedure."

אתם מוזמנים להמשיך לקרוא ואף לראות את הקוד שהוא יצר אצלו בפוסט.

חדשות Firebird

החדשות המרעישות ביותר שיש לעולם הFirebird כיום, הם לא הרבה תוספות ושיפורים של גרסה 3, אלא דווקא תיקון 3 באגים בעולם ה PHP אשר היו קיימים מזה הרבה מאוד שנים.

החל מגרסה 5.3.9, התמיכה של PHP ב Firebird באמצעות PDO סוף כל סוף מתפקדת כמו שצריך, ועכשיו ניתן יהיה להשתמש ב binding למשל, ולא יהיו יותר בעיות בין אותיות קטנות וגדולות. גם הספירה של כמות השדות תהיה נכונה, ולא תציג פחות תוצאות ממה שיש באמת.

כל הבאגים האלו, חיכו הרבה מאוד שנים לפתרון, וסוף כל סוף הם קיבלו מענה.

בנוסף, אפשר להתחיל להנות מהרצאות על Firebird ובכלל סרטונים על Firebird בערוץ SQLFirebird ב Youtube.

תהנו מהרצאה של Ann Harrison (אחת מהממציאים של מסד הנתונים המקורי):

קישור ל"מדוע firebird עדיף מOracle"

כותב הבלוג Backwards compatible, מנהל למעלה מ600 מסדי נתונים מבית אורקל, ו60 מסדי נתונים של Firebird, מסביר מדוע לדעתו Firebird הוא מסד נתונים שעדיף לכם לקחת עבור העסק שלכם, במקום אורקל.

Common Table Expression

בתקן SQL 99, נוספה תמיכה לביטוי רב עוצמה אשר קיבל את השם Common Table Expression או CTE בקיצור.

נכון לזמן כתיבת הפוסט הזה, ישנם מעט מאוד מסדי נתונים אשר תומכים בזה, כאשר בעולם הקוד הפתוח אני מכיר רק 2 שהם Firebird ו PostgreSQL.

CTE בעצם מאפשר לנו ליצור מעין טבלה זמנית עבור code block של SQL. כלומר נגיד ויש select קבוע שאני רוצה עליו לבצע עוד select, אבל הselect המקורי מכיל כל מיני תנאים וכו', ויותר מזה, יכול להיות שאני רוצה להשתמש באותה שאילתא ביותר ממקום אחד, אז CTE בעצם נכנס לשימוש. הוא יודע להגיע ב"טעם" רגיל וב"טעם" שהוא רקורסיבי:

with Machines as (
  select id, type, name, ip
from Computers
where type in (1, 8, 34) and ip like '192.168%'
);

select user
from CompanyUsers cu
left join Machines on cu.machine = Machines.id;

עוד צורת שימוש שיש ל CTE היא בצורה רקורסיבית על המידע:

with recursive
  dept_year_budget as (
    select fiscal_year,
           dept_no,
           sum(projected_budget) as budget
    from proj_dept_budget
    group by fiscal_year, dept_no
  ),
  dept_tree as (
    select dept_no,
           head_dept,
           department,
           cast('' as varchar(255)) as indent
    from department
    where head_dept is null
    union all
    select d.dept_no,
           d.head_dept,
           d.department,
           h.indent || '  '
    from department d
         join dept_tree h on d.head_dept = h.dept_no
  )
select d.dept_no,
       d.indent || d.department as department,
       dyb_2008.budget as budget_08,
       dyb_2009.budget as budget_09
from dept_tree d
     left join dept_year_budget dyb_2008
       on d.dept_no = dyb_2008.dept_no
       and dyb_2008.fiscal_year = 2008
     left join dept_year_budget dyb_2009
       on d.dept_no = dyb_2009.dept_no
       and dyb_2009.fiscal_year = 2009