Author Topic: python-tokyocabinet  (Read 1049 times)

Ahmed Youssef

  • Helping Freak
  • Administrator
  • Active Member
  • *****
  • Posts: 242
    • View Profile
    • WWW
    • Email
python-tokyocabinet
« on: July 21, 2009, 09:35:11 AM »
من كام يوم جالى تليفون فى منتصف الليل تقريبا وانا بلعب كورة :) من صديقى الصدوق Hackobacko بيدعونى للمشاركة فى اجتماع على ال IRC على قناة sowarna للبدأ فى المشاركة فى تطوير مشروع sowarna
http://code.google.com/p/sowarna/

فى مجموعة حاجات مثيرة للإهتمام فى المشروع زى thrift و

 Tokyo Cabinet وهى

هى مكتبة لإدارة قاعدة بيانات "ملف يحوى مجموعة من السجلات records” كل واحد منها عبارة عن مفتاح وقيمة.. انشئت لتحل مكان GDBM و QDBM وتتميز

حجم قاعدة البيانات اقل ،وسرعة معالجة، اداء عالى فى بيئة متعددة الخيوط، وAPI وبسيطة والعديد..

TokyoCabinet مكتوبة بلغة سى ومتوفرة لPerl, Ruby, Lua, Java , Python
** من http://tokyocabinet.sourceforge.net/

السجلات بيتم تنظيمها فى Hash table او شجرة B+ او فى مصفوفة محددة الطول -خارج اهتمامنا-

بالنسبة لقاعدة البيانات من Hash table او HDB يجب ان تكون كل المفاتيح فريدة -مستحيل تضيف سجلين بنفس المفتاح-
تقدر تتعامل بتخزين سجل مكون من مفتاح وقيمة، حذف، الحصول على سجل عن طريق المفتاح.. او حتى امكانية المرور على كل مفتاح.

قاعدة البيانات من شجرة B+ او BDB نفس السابقة ولكن تسمح بإمكانية وجود اكثر من سجل بنفس المفتاح. ويتم تخزين السجلات عن طريق دالة مقارنة يحددها المستخدم

1- الإعداد ابحث عن tokyocabinet فى مدير الحزم وقم بتستيبها .. اذا فضلت التستيب اليدوى قم بتحميل الملفات المصدرية واتبع ملف ال README او INSTALL
2- قم بتستيب pytc بإستخدام easy_install او بأى طريقة تريحك

نقوم بالتجربة
1- استدعى tc
Code: [Select]
>>> import tc 
2- شوف الإصدار اللى عندك
Code: [Select]
>>> tc.__version__ 
'0.7.2'

3- جميل عايزين نشوف ايه الأنواع المتاحة عندنا
Code: [Select]
>>> filter(lambda x: x.endswith("DB"), dir(tc)) 
['BDB', 'HDB']
جميل عندنا B+ Tree و عندنا Hash table

4- ننشئ ملف وليكن ارقام تليفونات ونحدد المود "OCREAT” للإنشاء او "OWRITER” للكتابة
Code: [Select]
>>> hdb=tc.HDB("phonesdb", tc.HDBOWRITER|tc.HDBOCREAT) 
>>> hdb
<tc.HDB object at 0xb7fd75d8>

5- عندنا شوية ميثودز مهمة
open لفتح الداتابيز -زى ماتم استخدامها فى المشيّد-
close لغلق الداتابيز
path هو مسار الداتابيز
put لتخزين سجل
get للحصول على سجل
out حذف سجل
vanish حذف كل السجلات
rnum للحصول على عدد السجلات.. مع len نفس الشئ
iterinit لتجهيز الiterator
iternext للحصول على العنصر التالى فى ال iterator
ecode للحصول على اخر ايرور
errmsg للحصول على رسالة واضحة عن -رقم الإيرور-
addint/adddouble لإضافة int او double
tranbegin لبدا transaction
trancommit للتنفيذ
tranabort لإلغاءه
fsiz للحصول على مساحة الداتابيز


بخصوص ال bdb فليها بعض الميثودز الخاصة زى
getlist للحصول على كل السجلات بمفتاح معين
outlist لحذف كل السجلات بمفتاح معين
putlist لوضع مجموعة من السجلات "مجموعة قيم ذات مفتاح واحد"
putdup وضع سجل مع سماحية تكرار المفتاح


السجلات الإبتدائية
Code: [Select]
>>> hdb.put("ahmed", "012352132 ") 
>>> hdb.put("khaled", "013245123")
>>> hdb.put("ayman", "0231312")
>>> hdb.put("salma", "011124642")

الحصول على سجل
Code: [Select]
>>> hdb.get("ayman") 
'0231312'
الحصول على كل السجلات بالطريقة البايثونية وهى اللى تهمنا
Code: [Select]
>>> for key,value in hdb.iteritems(): 
...     print key, value
...
ahmed 012352132
khaled 013245123
ayman 0231312
salma 011124642

الطريقة الأخرى بإستخدام iterinit و iternext تقدر تراجع وثائق tokyocabinet للحصول على مثال

حذف سجل
Code: [Select]
>>> hdb.out("khaled") 

قفل الداتابيز
Code: [Select]
>>> hdb.close() 

Logged

Life is just a chance to grow a soul. - A. Powell
Weblog: http://ahmedyoussef.wordpress.com/

hackobacko

  • Out of control
  • Global Moderator
  • Just Joined
  • *****
  • Posts: 8
    • View Profile
And here's most of the API
« Reply #1 on: July 22, 2009, 11:20:49 AM »
-----------------------------------------------------------------------------------------------------------
irc من يحب المشاركة فى هذا المشروع المتميز والاوبن سورس فنحن نلتقى على
server:www.freenode.net
channel:sowarna


  او راسلنى   Ahmed Youssef  إذا كان لديك استفسار عن الميعاد فقط راسل

تنويه : المعلومات التالية نتيجة بحث مكثف فى المشروع وبالتالى هى تخص هذا المشروع

إذا أردت الاستفادة وكنت تريد المشاركة فى مشروع متميز واوبن سورس فلا  تردد

---------------------------------------------------------------------------------------------------------------------
installing tokyocabinet from source

   download "zlib", get it from http://www.zlib.net/ and get it installed
   [ if not already installed in your system]

   download libbz2 and get it installed
   [if you're using redhat/fedora systems you've to make sure libbz2-
   dev(el) installed also - thanks to Ahmed Soliman www.ahmedsoliman.com]

   download tokyocabinet, last version from http://tokyocabinet.sourceforge.net/misc/
   [./configure   make   make install]


   download pytc, http://pypi.python.org/pypi/pytc/ and get it installed
   [./setup.py build        ./setup.py install]

for pytc, you can install it using another method :


   
Code: [Select]
   cd pytc
   python setup.py build_ext -i -f
   export PYTHONPATH=$PWD:$PYTHONPATH
   then you're able to use the library from this path, meaning when you import pytc, it will be
   actually imported from this path .

usage:

So far w3're only concerned about the B+ Tree database so we're g0nna use 'BDB'

BDBCUR cursor is a mechanism to access each record of B+ tree database in ascending or descending order.

 
Code: [Select]
   import pytc as tc
   bTreeDataBase = tc.BDB()

   open database, if not exists create it and open it - open(string file, mode)

Code: [Select]
   bTreeDataBase.open("dict.db", tc.BDBOWRITER | tc.BDBOCREAT)  
    bTreeDataBase.put("key1", "1")
    bTreeDataBase.put("key2", "2")
   
   bTreeDataBase.adddouble("key3", 45.5)  # add double value
   bTreeDataBase.addint("key4", 45)          # add int value
   bTreeDataBase.putdup("key1", "11")

   for key, value in bTreeDataBase.iteritems():       #iterate through items
       print(key, value)

   ('key1', '1')
   ('key1', '11')
   ('key2', '2')
   ('key3', '\x00\x00\x00\x00\x00\xc0F@')
   ('key4', '-\x00\x00\x00')


   for key in bTreeDataBase.iterkeys():
       print(key)

   key1
   key1
   key2
   key3
   key4


   for val in bTreeDataBase.itervalues():
       print(val)

   1
   11
   2
   �F@
    -


   bTreeDataBase.items()

   [('key1', '1'),
   ('key1', '11'),
   ('key2', '2'),
   ('key3', '\x00\x00\x00\x00\x00\xc0F@'),
   ('key4', '-\x00\x00\x00')]

   
   
Code: [Select]
      bTreeDataBase.get("key1")       # result is 1
      bTreeDataBase.getlist("key1")   #get a list of all values assigned to a key, the result ['1', '11']

   
Code: [Select]
   bTreeDataBase.copy("/root/newLocationOfDataBase.db")  #copy to new location

   !ls /root | grep new*
   -rw-r--r--  1 root root   135680 2009-07-22 01:49 newLocationOfDataBase.db


   
Code: [Select]
   bTreeDataBase.path()  # retrieves path of database file
Code: [Select]
    bTreeDataBase.out("key1")    # removes 1st occurance of key and its value
    bTreeDataBase.items()

   [('key1', '11'),
    ('key2', '2'),
    ('key3', '\x00\x00\x00\x00\x00\xc0F@'),
    ('key4', '-\x00\x00\x00')]

   bTreeDataBase.getlist("key1") #output is  ['11']

   
     
Code: [Select]
bTreeDataBase.putdup("key1", "4")
     bTreeDataBase.outlist("key1")         #removes all ocurances of a key
     bTreeDataBase.items()

  [('key2', '2'),
  ('key3', '\x00\x00\x00\x00\x00\xc0F@'),
  ('key4', '-\x00\x00\x00')]


put cat to concatenate the value of an existing key to the end of the record,   if key doesn't exist it is added


suppose the result of invoking :    bTreeDataBase.items()   is

Code: [Select]
[('key2', '2'),
 ('key3', '\x00\x00\x00\x00\x00\xc0F@'),
 ('key4', '4'),
 ('key5', '5'),
 ('key8', '8'),
 ('key9', '9')]

then

Code: [Select]
bTreeDataBase.putcat("key8", "7")
bTreeDataBase.items()

[('key2', '2'),
 ('key3', '\x00\x00\x00\x00\x00\xc0F@'),
 ('key4', '4'),
 ('key5', '5'),
 ('key8', '87'),   # aaaaaaaaah ,     wow !
 ('key9', '9')]

Now we can do :
Code: [Select]
bTreeDataBase.putkeep("key10", "10")  # store a new key 
bTreeDataBase.putlist("key10", ['2','9'])   # don't forget to add quotes ' ' infront and end of the items,
                                              otherwise you'll not get an error but the record will not be added

bTreeDataBase.getlist("key10")  # ['10', '2', '9']

Now we have the method :

Quote
range( string bkey, boolean binc, string ekey,  boolean einc, int max)

bkey - the key of the beginning border. If it is `null', the first record is specified.
binc - whether the beginning border is inclusive or not.
ekey - the key of the ending border. If it is `null', the last record is specified.
einc - whether the ending border is inclusive or not.
max - the maximum number of keys to be fetched. If it is negative, no limit is specified.
Code: [Select]
bTreeDataBase.range(None, True, None, True, 3)
['key10', 'key2', 'key3']

bTreeDataBase.range(None, False, None, True, 3)
['key10', 'key2', 'key3']

bTreeDataBase.range(None, False, None, False, 3)
['key10', 'key2', 'key3']

bTreeDataBase.range(None, False, None, False, 4)
['key10', 'key2', 'key3', 'key4']

bTreeDataBase.range('key2', False, None, False, 4)
['key3', 'key4', 'key5', 'key8']

bTreeDataBase.range('key2', True, None, False, 4)
['key2', 'key3', 'key4', 'key5']

Now suppose when we invoke bTreeDataBase.items() we have :

Code: [Select]
[('key10', '555'),
 ('key10', '5678'),
 ('key2', '2'),
 ('key3', '\x00\x00\x00\x00\x00\xc0F@'),
 ('key4', '4'),
 ('key5', '5'),
 ('key8', '87'),
 ('key9', '9')]

Now we can do :

Code: [Select]
bTreeDataBase.vsiz("key10")      # size of 1st occurance   which is 3
bTreeDataBase.vnum("key10")    # number of records concerning a key which is  2

You also can do :
   
Code: [Select]
bTreeDataBase.values()
['555', '5678', '2', '\x00\x00\x00\x00\x00\xc0F@', '4', '5', '87', '9']

bTreeDataBase.keys()
['key10', 'key10', 'key2', 'key3', 'key4', 'key5', 'key8', 'key9']

bTreeDataBase.vanish()  -> remove all records
« Last Edit: July 27, 2009, 03:10:00 PM by hackobacko »
Logged

hackobacko

  • Out of control
  • Global Moderator
  • Just Joined
  • *****
  • Posts: 8
    • View Profile
Re: python-tokyocabinet
« Reply #2 on: July 26, 2009, 07:00:38 PM »
remotely على نفس الجهاز دون استخدامها   library لغاية الوقتى كل اللى عملناه اننا تعاملنا مع ال

tokyotyrant الوضع ده هيتغير الآن إذا قمنا بتستيب ال 

وهو السيرفر اللى من خلاله هنقدر نتعامل مع الداتبيز بتاعتنا وهتلاقيه هنا
http://tokyocabinet.sourceforge.net/misc/
  الموجودة فى المسار ده لو حصل معاك خطأ اثناء الست اب dependencies  من المستحسن انك تستب كل ال 

انا نفسى حصل معايا خطأ اثناء عمل ست اب للسيرفر لانه ببساطة مكنتش مستب احدث
 tokyocabinet نسخة من ال 

جدير بالذكر انه التوتوريال اللى هقولها هنا هى اختصار للتوتوريال الأصلية
http://tokyocabinet.sourceforge.net/tyrantdoc/
 B+ Tree databaseواللى هلخص فيها اللى يهمنا وهو التعامل مع

to start server use :-

Code: [Select]
   ttserver -dmn /tmp/myDataBase.tcb 
# -dmn  -> run server as daemon
# suffix ".tcb" means we want a B+ Tree database, there're other suffixes
# for other types of databasesbut all we concern is B+ Tree databases

for server auto start add this line to /etc/rc.d/rc.local

Code: [Select]
/usr/local/sbin/ttservctl start

tcrmgr  من الجدير بالذكر أيضا أن السيرفر يأتى معه أداة 
 locally للتحكم فى السيرفر
backup & restore ويمك استخدامها فى عملية ال
مثال

Code: [Select]
[terminal-1]$ mkdir ulog
[terminal-1]$ ttserver -ulog ulog casket.tch
[terminal-2]$ tcrmgr put localhost one first
[terminal-2]$ tcrmgr put localhost two second
[terminal-2]$ tcrmgr put localhost three third
#Terminate the server by Ctrl-C and remove the database.
[terminal-1]$ rm casket.tch
terminal-1]$ mv ulog ulog-back
[terminal-1]$ mkdir ulog
[terminal-1]$ ttserver -ulog ulog casket.tch
[terminal-2]$ tcrmgr restore localhost ulog-back
[terminal-2]$ tcrmgr mget localhost one two three 

one     first
two     second


Now the library used to access the database remotely

 http://code.google.com/p/pytyrant/source/checkout


Code: [Select]
#download from svn
svn checkout http://pytyrant.googlecode.com/svn/trunk/ pytyrant-read-only
or
http://pypi.python.org/pypi/pytyrant/1.1.17
#install
python setup.py build
python setup.py install

Code: [Select]
import pytyrant as pt
con = pt.PyTyrant.open('127.0.0.1', 1978)
con['frinds'] = 'Hamdy, Ahmed, Ahmed, Raed'
print(con['frinds'])  -->    #Hamdy, Ahmed, Ahmed, Raed
con.items()

[('one', 'first'),
 ('two', 'second'),
 ('three', 'third'),
 ('frindes', 'Hamdy, Ahmed, Ahmed, Raed')]


« Last Edit: July 26, 2009, 07:35:55 PM by hackobacko »
Logged

hackobacko

  • Out of control
  • Global Moderator
  • Just Joined
  • *****
  • Posts: 8
    • View Profile
Now we're gonna go d33per into memcaching
« Reply #3 on: July 27, 2009, 06:43:15 AM »
memcached server
الموضوع نتيجة بحث فى صفحات كتير على الانترنت يعنى انا مش مخترعه وهحاول على قدر الإمكان اذكر المصادر لكن لو مذكرتهاش كلها هيبقى غصب عنى اكيد


Distributed memory object caching system هى


dynamic database driven websites يستخدم بصفة رئيسبة فى تخسين أداء ال
 للداتابيز فبدلا من عمل نداءات للداتبيز نفسها يتم الحصول على الداتا من الذاكرة calls  للداتبيز فى الذاكرة لتقليل الوقت الازم لعمل caching  عن طريق عمل

 تواجه ضغطا رهيبا على سيرفراتها لأن عدد الزائرين يوميا كان مهولا فلجأت لهذه الفكرة     livejournal.com هذه الفكرة جاءت عندما كانت أحد الشركات وهى
وكانت النتائج مذهلة بالطبع حيث انخفض الضغط على الداتابيز سيرفرز لها بشكل كبير جدا
حتى مع وجود ضغط كبير فلها سرعة كبيرة فنحن نتعامل مع الرام للجهاز وهى سريعة للغاية
وسرعة الاستجابة للمستخدم أيضا تكون جيدة جدا


 التى يمكنها التعامل معها بعدة لغات برمجة مختلفةclients عموما يمكنك مراجعة هذه الصفحة
لمزيد من المعلوما عن هذه السيرفرات وال

http://code.google.com/p/memcached/


memcached server الموقع الرئيسى ل
http://www.danga.com/memcached/


 نفسها tokyocabinet  ولكننا سنقصر بحثنا هذا على وجود هذه الخاصية فى ال
memcahing servers  هناك أنواع من ال

بعض العيوب لمثل هذه السيرفرات

http://www.lshift.net/blog/2009/05/21/memcached-protocol-is-not-enough#more-416

ممكن اتناول اللى جاء فى الموضوع ده بشىء من الإيجاز واللى عايز أكتر ممكن يقرأه

Memcached ought to be a caching layer

يعنى لو السيرفر وقف طبعا الكاششينج ده هيتوقف
 لكن لو بيتم التعامل معاه على انه caching layer وده هيبقى مقبول لو انت بتتعامل مع  فده مش هيبقى مقبول لانه كدة هتعمل بطء شديد فى السيرفرات عندك لو مش شغالة
persistent storage. السيرفر على انه 

لمزيد من الفهم شوف المثال ده ومتقلقش لاننا هنوضحه بعد كدة  المهم الفكرة العامة

Code: [Select]
>>> mc.set('key', 'value')
True
>>> os.system(’killall memcached’)
>>> mc.set(’key’, ‘value2′)
False  # this's normal


But for example a ruby client , just ignore errors:


Code: [Select]
irb(main):003:0> cache = MemCache::new '127.0.0.1:11211'
irb(main):004:0> cache["key"] = “value”
=> “value”
$ killall memcached
irb(main):005:0> cache["key"] = “value”
=> “value”    --> This's not accepted if we're using memcache as a persistent storage got the idea ? !!

(2) Optimistic locking: versioning

 واحد  key   بيعملو ابديت ل  client تخبل عند كذا
 race condition كدة هيبقى عندك
 version numbers for records والحل

Code: [Select]
def versioned_set(key, value):
version = mc.incr(’%s.version’ % (key,))
return mc.set(’%s.%s’ % (key, version), value)

def versioned_get(key):
version = mc.get(’%s.version’ % (key,))
return mc.get(’%s.%s’ % (key, version))

اعتقد الكود واضح

 set - incr operations ? ولكن عيب الطريقة دى مثلا بو الكونيكشن قطع واليوزر بين عمليتين  implement for optimistic locking  لوبكدة نكون عملنا 

طبعا هتحصل فوضى

server side
علشان كدة انسب طريقة للموضوع ده اننا نعمله على ال

3 - memcached using text protocol is slower than using binary protocol
     since it's longer and requires further processing fo text to detect
     newline characters

 علشان يتم التغلي على مثل هذه المشاكل binray protocol المهم انه الحل السحرى كان استخدام



text protocol specifications : http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt

binary protocol specifications : http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol

خد بالك الموقع اللى فات ده مليان معلومات عن الموضوع ده وده مصدر رئيسى للتوتوريال دى

لازم نستخدم كلاينت يدعم الموضوع ده  tokyotyrant  او tokyocabinet المهم بقى
علشان نكلم

الموقع ده فى ليست بالكلاينتس اللى ممكن تستخدمهم ف لغات برمجة عديدة
http://code.google.com/p/memcached/wiki/Clients

اللى يهمن البايثون وهناخد أول واحد فى الليست الخاصة بلغة بايثون

  من  ftp client نزل الكود باستخدام اى 
ftp://ftp.tummy.com/pub/python-memcached

Code: [Select]
python setup.py build
python setup.py install

example on usage
Code: [Select]
#!/usr/bin/env python

import pytc as tc
import memcache

mc = memcache.Client(['127.0.0.1:1978'], debug=0)

bTreeDataBase = tc.BDB()
bTreeDataBase.open("dict.db", tc.BDBOWRITER | tc.BDBOCREAT) 
bTreeDataBase.put("key1", "1")
bTreeDataBase.put("key2", "2")

mc.set("some_key", "Some value")
value = mc.get("some_key")
mc.set("another_key", 3)
mc.delete("another_key")
mc.set("key", "1")   # note that the key used for incr/decr must be a string.
mc.incr("key")
mc.decr("key")


def getMyValue(key):
obj = mc.get(key) #trying to get from memcache
if not obj:# if not try to get from database but 1st add it to memcache
valFromDatabase = tc.get(key)
mc.set(key, valFromDatabase)       # may be in another thread for no end-user latency
return tc.get(key)

def setMyValue(key, value):     # set key,value ppair or update them
if mc.set(key, value):
tc.set(key, value)                # may be in another thread


print(getMyValue("key"))

# similarly when deleting an item, we 1st delete it from cache then database

Code: [Select]
شوية حاجات لازم توضع فى الاحتياط عندما تتعامل مع مثل هذه الكلاينتس

 والكلاينت الذا شرحناه بالإعلى لا يستخدم ذلك لسوء الحظ  binary protocol يفضل
استخدام كلاينت يتعامل مع

binaryu protocol ممكن تجرب الكلاينت التالى وهو يتعامل مع

Code: [Select]
svn checkout http://ziutek.googlecode.com/svn/trunk/ binmemcache   
               

 هناك الأولitems   وتشوف ال  cache على الداتابيز لازم تشيك الأول على ال  query
قبل أى

لو موجودة رجعها لو مش موجوده هاتها وحطها فى الكاش بعدين رجعها لليوزر

ولكن هذا الكلام لو انت بتتعامل مع داتابيز تانية  partial updates  لا تدعم ال  tokyocabinet لو حد بيعمل ابديت لحاجة معينة وللأسف
  من الكاش وبعدين اعملها ابديت وبكدة لما ييجى المستخدم يجيبها مش هتبقى فى الكاش فتيجى من الداتابيز وتتحط فى الكاش نسخة محدثة منها   item امسح ال

 udp  او  tcp  الاتصال بين الكلاينت و السيرفر ممكن يبقى
 بدل ما يقفلوها ويفتحوها كل شوية  connections ويستحسن للكلاينتس أن تقوم بعمل كاشينج لل
  مجهزة للتعامل مع أكثر من ألف اتصال  memcaching servers كمان لازم تعرف انه ال  overhead لأن ده بيسبب

establishing connections is an overhead, so caching them is efficient


 لازم تأمنها كويس ومتسمحش لأجهزةمن برة النتورك بتاعتها بأخذ أكسس عليها
memcaching servers وأخيرا لازم تعرف انه ال

« Last Edit: July 28, 2009, 01:44:26 AM by St0rM »
Logged