summaryrefslogtreecommitdiff
path: root/heap/ebus/datastore.py
blob: 66303f3ed7f84c159656653d74d90abf197337d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#
import os
from threading import Lock
import tables
import logging

class ValueFloat(tables.IsDescription):
        timestamp = tables.Time32Col() #index on Time64 is broken on pytables 2.4
        value = tables.Float32Col()

class ValueInt(tables.IsDescription):
        timestamp = tables.Time32Col()
        value = tables.Int32Col()

class ValueString(tables.IsDescription):
        timestamp = tables.Time32Col()
        value = tables.StringCol(20)


class Datastore(object):
        def __init__(self,basepath):
                self.basepath = basepath
                self.files = {}
                self.fileLock = Lock()
                self.tables = {}

        # list all table in a dictionary { path.dot.name : object }
        def listTables(self):
                return dict(map(lambda e: (e.title, e), self.files.root))

        def __enter__(self):
                self.fileLock.__enter__()

        def __exit__(self, *a):
                self.fileLock.__exit__(*a)

        def getTable(self, name, klass=None):
                name = name.replace(".","_")
                with self.fileLock:
                        if not name in self.files:
                                path = os.path.join(self.basepath, name+".hdf")
                                print "open {0}".format(path)
				if os.path.exists(path):
					self.files[name] = tables.openFile(path, "a", title = "eBus Datastore")
				elif klass:
					self.files[name] = tables.openFile(path, "w", title = "eBus Datastore")
				else:
					raise Exception("No such sensor {0}".format(name))

                        if not name in self.tables:
                                t = None
                                try:
                                        t = self.files[name].getNode("/"+name)
                                except tables.NoSuchNodeError,e:
                                        if not klass: raise e

                                        t = self.files[name].createTable("/",
                                                        name,
                                                        klass,
                                                        'Description ' + name,
                                                        filters=tables.Filters(complevel=1),
                                                        createparents=True)
                                        t.cols.timestamp.createCSIndex()

                                self.tables[name] = t

                        return self.tables[name]

        def addValue(self, name, ts, value, klass):
                t = self.getTable(name, klass)
		if klass != None:
		    assert klass.columns['value'].type == t.cols.value.type, "Type check failed"

                with self.fileLock:
                        t.row['timestamp'] = ts
                        t.row['value'] = value
                        t.row.append()

        def addValueInt(self, name, ts, value): self.addValue(name, ts, value, ValueInt)
        def addValueString(self, name, ts, value): self.addValue(name, ts, value, ValueString)
        def addValueFloat(self, name, ts, value): self.addValue(name, ts, value, ValueFloat)

        def flush(self):
                with self.fileLock:
                        for file in self.files.values():
				logging.debug("flush file: %s" % file.filename)
                                file.flush()

        def flush_table(self,name,table,close=False,index=False):
		if close or table.cols.timestamp.index.nelements == 0:
			logging.debug("close table: %s" % table.name)
			name = name.replace(".","_")
			#close file after first insert
			#to force a index build on re-open
			self.tables.pop(name).close()
			self.files.pop(name).close()
		elif 'row' in table.__dict__:
			logging.debug("flush buffer {name}".format(name=name))
			table.row._flushBufferedRows()

			if index and table.indexed and table.autoIndex:
				logging.debug("index {name}".format(name=name))
			       # Flush any unindexed row
				rowsadded = table.flushRowsToIndex(_lastrow=True)
				if table._dirtyindexes:
					# Finally, re-index any dirty column
					table.reIndexDirty()



        def close(self):
                with self.fileLock:
                        for file in self.files.values():
                                file.close()