Move all the khashmir database operations to a separate module.
[quix0rs-apt-p2p.git] / apt_dht_Khashmir / db.py
1
2 from time import time
3 import sqlite  ## find this at http://pysqlite.sourceforge.net/
4 import os
5
6 class DBExcept(Exception):
7     pass
8
9 class DB:
10     """Database access for storing persistent data."""
11     
12     def __init__(self, db):
13         self.db = db
14         try:
15             os.stat(db)
16         except OSError:
17             self._createNewDB(db)
18         else:
19             self._loadDB(db)
20         
21     def _loadDB(self, db):
22         try:
23             self.store = sqlite.connect(db=db)
24             #self.store.autocommit = 0
25         except:
26             import traceback
27             raise DBExcept, "Couldn't open DB", traceback.format_exc()
28         
29     def _createNewDB(self, db):
30         self.store = sqlite.connect(db=db)
31         s = """
32             create table kv (key binary, value binary, time timestamp, primary key (key, value));
33             create index kv_key on kv(key);
34             create index kv_timestamp on kv(time);
35             
36             create table nodes (id binary primary key, host text, port number);
37             
38             create table self (num number primary key, id binary);
39             """
40         c = self.store.cursor()
41         c.execute(s)
42         self.store.commit()
43
44     def getSelfNode(self):
45         c = self.store.cursor()
46         c.execute('select id from self where num = 0;')
47         if c.rowcount > 0:
48             return c.fetchone()[0]
49         else:
50             return None
51         
52     def saveSelfNode(self, id):
53         c = self.store.cursor()
54         c.execute('delete from self where num = 0;')
55         c.execute("insert into self values (0, %s);", sqlite.encode(id))
56         self.store.commit()
57         
58     def dumpRoutingTable(self, buckets):
59         """
60             save routing table nodes to the database
61         """
62         c = self.store.cursor()
63         c.execute("delete from nodes where id not NULL;")
64         for bucket in buckets:
65             for node in bucket.l:
66                 c.execute("insert into nodes values (%s, %s, %s);", (sqlite.encode(node.id), node.host, node.port))
67         self.store.commit()
68         
69     def getRoutingTable(self):
70         """
71             load routing table nodes from database
72             it's usually a good idea to call refreshTable(force=1) after loading the table
73         """
74         c = self.store.cursor()
75         c.execute("select * from nodes;")
76         return c.fetchall()
77             
78     def retrieveValues(self, key):
79         c = self.store.cursor()
80         c.execute("select value from kv where key = %s;", sqlite.encode(key))
81         t = c.fetchone()
82         l = []
83         while t:
84             l.append(t['value'])
85             t = c.fetchone()
86         return l
87
88     def storeValue(self, key, value):
89         """Store or update a key and value."""
90         t = "%0.6f" % time()
91         c = self.store.cursor()
92         try:
93             c.execute("insert into kv values (%s, %s, %s);", (sqlite.encode(key), sqlite.encode(value), t))
94         except sqlite.IntegrityError, reason:
95             # update last insert time
96             c.execute("update kv set time = %s where key = %s and value = %s;", (t, sqlite.encode(key), sqlite.encode(value)))
97         self.store.commit()
98
99     def expireValues(self, expireTime):
100         """Expire older values than expireTime."""
101         t = "%0.6f" % expireTime
102         c = self.store.cursor()
103         s = "delete from kv where time < '%s';" % t
104         c.execute(s)
105         
106     def close(self):
107         self.store.close()