More work on code samples, Python implementation of the API using Berkeley DB.

--HG--
branch : mjc
rename : examples/c/ex_hello.c => examples/c/ex_cursor.c
rename : examples/c/ex_hello.c => examples/c/ex_extending.c
rename : examples/c/ex_hello.c => examples/c/ex_pack.c
rename : examples/c/ex_hello.c => examples/c/ex_process.c
rename : examples/c/ex_hello.c => examples/c/ex_transaction.c
This commit is contained in:
Michael Cahill
2011-01-06 10:57:13 +11:00
parent e51557e46f
commit c823027e57
27 changed files with 623 additions and 52 deletions

34
lang/python/src/server.py Normal file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python
# WiredTiger Python RPC server for testing and tutorials.
# Copyright (c) 2011 WiredTiger, Inc. All rights reserved.
import sys
from wiredtiger.service import WiredTiger
from wiredtiger.service.ttypes import *
from wiredtiger.impl import *
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
class WiredTigerHandler:
handler = WiredTigerHandler()
processor = WiredTiger.Processor(handler)
transport = TSocket.TServerSocket(9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
# We could do one of these for a multithreaded server
#server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
#server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)
print 'Starting the server...'
server.serve()
print 'done.'

View File

@@ -0,0 +1,212 @@
# WiredTiger API implementation
'''
WiredTiger Python API implementation.
'''
import struct
from urlparse import urlparse
from wiredtiger import pack, unpack
from wiredtiger.util import parse_config
# Import the BDB symbols with the 'db.' prefix, it avoids polluting the
# namespace of this package
from bsddb3 import db
class Table:
def __init__(self, db, name, key_format='u', value_format='u', columns=(,), column_sets=(,), indices=(,)):
self.db = db
self.name = name
self.key_format = key_format
self.value_format = value_format
self.columns = columns
self.column_sets = column_sets
self.indices = indices
def close(self):
self.db.close(db.DB_NOSYNC)
def check_schema(self, key_format='u', value_format='u', columns=(,), column_sets=(,), indices=(,)):
if (self.key_format != key_format or
self.value_format != value_format or
self.columns != columns or
self.column_sets != column_sets or
self.indices != indices):
raise 'Schemas don\'t match for table "' + self.name + '"'
class Cursor:
def __init__(self, session, table):
self.session = session
self.table = table
self.key_format = table.key_format
self.value_format = table.value_format
self.dbc = table.db.cursor()
def close(self, config=''):
self.dbc.close()
self.session.cursors.remove(self)
def get_key(self):
return unpack(self.key_format, self.key)
def get_value(self):
return unpack(self.key_format, self.value)
def set_key(self, *args):
self.key = pack(self.key_format, *args)
def set_value(self, *args):
self.value = pack(self.value_format, *args)
def first(self):
self.key, self.value = self.dbc.first()
def last(self):
self.key, self.value = self.dbc.last()
def next(self):
self.key, self.value = self.dbc.next()
def prev(self):
self.key, self.value = self.dbc.prev()
def search(self):
searchkey = self.key
self.key, self.value = self.dbc.set_range(self.key)
return (self.key == searchkey)
def insert(self):
self.dbc.put(self.key, self.value)
return self.key
def update(self):
self.dbc.put(self.key, self.value, db.DB_CURRENT)
def delete(self):
self.dbc.delete()
class Session:
def __init__(self, conn, id):
self.conn = conn
self.cursors = []
self.tables = {'schema' : conn.schematab}
def _close_cursors(self):
# Work on a copy of the list because Cursor.close removes itself
for c in self.cursors[:]:
c.close()
def close(self, config=''):
self._close_cursors()
self.conn.sessions.remove(self)
def open_cursor(self, uri, config=''):
c = self.conn._open_cursor(self, uri, config)
self.cursors.append(c)
return c
def dup_cursor(self, c, config=''):
dupc = c.dup()
self.cursors.append(dupc)
return dupc
def _open_table(self, name):
schema_cur = Cursor(self, self.conn.schematab)
schema_cur.set_key(name)
if schema_cur.search():
k, v, c, cset, idx = schema_cur.get_value()
c = tuple(parse_config(c))
cset = tuple(parse_config(cset))
idx = tuple(parse_config(idx))
self.tables[name] = Table(k, v, c, cset, idx)
def create_table(self, name, config=''):
schema = {}
for k, v in parse_config(config):
if k in ('key_format', 'value_format', 'columns'):
schema[k] = v
elif k == 'column_set':
schema['column_sets'] = schema.get('column_sets', (,)) + (v,)
elif k == 'index':
schema['indices'] = schema.get('indices', (,)) + (v,)
else:
raise 'Unknown configuration "' + k + '"'
if name in self.tables:
self.tables[name].check_schema(**schema)
# XXX else try to open the table and retry
def rename_table(self, oldname, newname, config=''):
pass
def drop_table(self, name, config=''):
pass
def truncate_table(self, name, start=None, end=None, config=''):
pass
def verify_table(self, name, config=''):
pass
def begin_transaction(self, config=''):
if self.cursors:
raise 'Transactions cannot be started with cursors open'
def commit_transaction(self):
self._close_cursors()
pass
def rollback_transaction(self):
self._close_cursors()
pass
def checkpoint(self, config=''):
pass
class Connection:
def __init__(self, uri, config=''):
url = urlparse(uri)
parts = url[1].split(':')
self.host = parts[0]
if len(parts) > 1:
port = int(parts[1])
else:
port = 9090
self.home = url[2]
self.sessions = []
self.env = db.DBEnv();
self.env.open(self.home,
db.DB_PRIVATE | db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_THREAD)
schemadb = db.DB(self.env);
schemadb.open("__wt_schema.db", None, db.DB_BTREE, db.DB_CREATE)
# The schema of the schema table.
self.schematab = Table(schemadb, key_format='S', value_format='SSSSS',
columns=('name', 'key_format', 'value_format', 'column_sets', 'indices'))
def close(self, config=''):
# Work on a copy of the list because Session.close removes itself
for s in self.sessions[:]:
s.close()
self.schematab.close()
self.env.close()
def version(self):
return ("WiredTiger Python API 0.0.1", 0, 0, 1)
def open_session(self, config=''):
s = Session(self, config)
self.sessions.append(s)
return s
def _open_cursor(self, session, uri, config):
if uri == 'table:':
return Cursor(session, self.schematab)
elif uri.startswith('table:'):
# XXX projections
return Cursor(session, session._get_table(uri[6:]))
# XXX application-specific cursor types?
raise 'Unknown cursor type for "' + uri + '"'

View File

@@ -0,0 +1,6 @@
import re
def parse_config(config):
for l in re.findall(r'(?:\(.*?\)|[^,])+', config):
for k, v in (l+"=yes").split('=')[0:2]:
yield (k.strip(), v.strip())