@@ -4,8 +4,9 @@ package main
4
4
5
5
import (
6
6
"time"
7
- // "reflect"
7
+ //"reflect"
8
8
"sort"
9
+ "strconv"
9
10
"sync"
10
11
11
12
"github.com/montanaflynn/stats"
@@ -14,7 +15,7 @@ import (
14
15
type dbItemT struct {
15
16
ColName string
16
17
ColType string
17
- ColVal float64
18
+ ColVal string
18
19
Time int64
19
20
}
20
21
@@ -31,12 +32,14 @@ func (q *dbQueueT) getChan() <-chan dbItemT {
31
32
}
32
33
33
34
type dbT struct {
34
- m map [int64 ][]dbItemT
35
+ m map [int64 ][]dbItemT
36
+ clicks map [uint8 ][]int64
35
37
}
36
38
37
39
func newDatabase () * dbT {
38
40
return & dbT {
39
- m : make (map [int64 ][]dbItemT ),
41
+ m : make (map [int64 ][]dbItemT ),
42
+ clicks : make (map [uint8 ][]int64 ),
40
43
}
41
44
}
42
45
@@ -45,7 +48,7 @@ func (c *dbT) Load(key int64) ([]dbItemT, bool) {
45
48
return val , ok
46
49
}
47
50
48
- func (c * dbT ) Add (key int64 , item dbItemT ) {
51
+ func (c * dbT ) AddMetric (key int64 , item dbItemT ) {
49
52
column , ok := c .Load (key )
50
53
if ! ok {
51
54
column = make ([]dbItemT , 0 , clickhouseMetricCount + 1 )
@@ -55,6 +58,48 @@ func (c *dbT) Add(key int64, item dbItemT) {
55
58
c .m [key ] = column
56
59
}
57
60
61
+ func (c * dbT ) AddClick (key uint8 , time int64 ) {
62
+ click , ok := c .clicks [key ]
63
+ if ! ok {
64
+ click = make ([]int64 , 0 , 10 )
65
+ }
66
+
67
+ click = append (click , time )
68
+ c .clicks [key ] = click
69
+ }
70
+
71
+ func (c * dbT ) popMetricsFrom (from int64 ) (rows map [string ][]float64 ) {
72
+ keys := make ([]int64 , 0 , len (c .m ))
73
+ for k := range c .m {
74
+ keys = append (keys , k )
75
+ }
76
+
77
+ sort .Slice (keys , func (i , j int ) bool { return keys [i ] < keys [j ] })
78
+ rows = make (map [string ][]float64 )
79
+ for _ , key := range keys {
80
+
81
+ if key >= from {
82
+ //log.Debugf("key [%d] %v", key, item);
83
+ for _ , item := range c .m [key ] {
84
+ rowKey := item .ColName + ":" + item .ColType
85
+ value , err := strconv .ParseFloat (item .ColVal , 64 )
86
+ if err != nil {
87
+ log .Errorf ("[%d] %s %s %s convert to float: %s" , item .Time , item .ColName , item .ColType , item .ColVal , err )
88
+ continue
89
+ }
90
+
91
+ rows [rowKey ] = append (rows [rowKey ], value )
92
+ }
93
+ delete (c .m , key )
94
+ } else {
95
+ // FIXME need send it too (its late data)
96
+ log .Warnf ("key [%d] %v" , key , c .m [key ])
97
+ }
98
+ }
99
+
100
+ return rows
101
+ }
102
+
58
103
var dbQueue dbQueueT
59
104
var database * dbT
60
105
var dbShutdownChan = make (chan bool )
@@ -68,45 +113,53 @@ func init() {
68
113
}
69
114
}
70
115
71
- func dbAddMetric (fieldName string , fieldType string , valueInterface float64 , time int64 ) {
116
+ func dbInsert (fieldName string , fieldType string , valueInterface string , time int64 ) {
72
117
dbQueue .Add (dbItemT {fieldName , fieldType , valueInterface , time })
73
118
}
74
119
75
- func dbAddEvent (fieldName string , fieldType string , valueInterface uint64 , time int64 ) {
76
- //dbQueue.Add(dbItemT{fieldName, fieldType, valueInterface, time})
120
+ func getClickTime (item dbItemT ) (timestamp int64 ) {
121
+ timestamp = item .Time
122
+ value , err := strconv .ParseUint (item .ColVal , 10 , 64 )
123
+ if err != nil {
124
+ // handle error
125
+ log .Errorf ("Cant convert to time %s %s %s convert to int: %s" , item .ColName , item .ColType , item .ColVal , err )
126
+ return timestamp
127
+ }
128
+
129
+ if value > 1000000000 {
130
+ timestamp = int64 (value )
131
+ }
132
+
133
+ return timestamp
77
134
}
78
135
79
136
func dbStore (item dbItemT ) {
80
137
//value := reflect.ValueOf(item.ColVal)
81
138
//valueType := value.Type()
82
139
log .Debugf ("DB [%d] %s:%s = %v" , item .Time , item .ColName , item .ColType , item .ColVal )
83
- database .Add (item .Time , item )
140
+ switch item .ColType {
141
+ case "count" :
142
+ if counterID , ok := configCounters [item .ColName ]; ok {
143
+ database .AddClick (counterID , getClickTime (item ))
144
+ } else {
145
+ log .Warn ("Unknown counter:" , item .ColName )
146
+ }
147
+ case "move" :
148
+ log .Warn ("MOVE" )
149
+ case "led" :
150
+ log .Warn ("LED" )
151
+ case "temp" , "humd" , "pres" :
152
+ database .AddMetric (item .Time , item )
153
+ default :
154
+ log .Warnf ("Unknown item.ColType: %s" , item .ColType )
155
+ }
84
156
}
85
157
86
- func dbDoTransfer () {
158
+ func dbSaveMetrics () {
87
159
now := time .Now ()
88
160
var timestamp = now .Unix ()
89
161
from := timestamp - 5
90
- keys := make ([]int64 , 0 , len (database .m ))
91
- for k := range database .m {
92
- keys = append (keys , k )
93
- }
94
-
95
- sort .Slice (keys , func (i , j int ) bool { return keys [i ] < keys [j ] })
96
- rows := make (map [string ][]float64 )
97
- for _ , key := range keys {
98
- if key >= from {
99
- //log.Debugf("key [%d] %v", key, item);
100
- for _ , item := range database .m [key ] {
101
- rowKey := item .ColName + ":" + item .ColType
102
- rows [rowKey ] = append (rows [rowKey ], item .ColVal )
103
- }
104
- delete (database .m , key )
105
- } else {
106
- // FIXME need send it too (its late data)
107
- log .Warnf ("key [%d] %v" , key , database .m [key ])
108
- }
109
- }
162
+ rows := database .popMetricsFrom (from )
110
163
111
164
row := make (map [string ]float64 ) // Result
112
165
nowrow := make (map [string ]float64 ) //next old row
@@ -133,23 +186,37 @@ func dbDoTransfer() {
133
186
go clickhouseMetricInsert (timestamp , row )
134
187
}
135
188
189
+ func dbProcessEvents () {
190
+ // TODO
191
+ // get current time in HH:mm
192
+ // create consumption speed stats
193
+ // save to db
194
+ }
195
+
136
196
// resend accomulated data to clickhouse in one row per sec
137
197
func dbLoop (ms uint32 ) {
138
198
dbWg .Add (1 )
139
199
defer dbWg .Done ()
140
200
ticker := time .NewTicker (time .Millisecond * time .Duration (ms ))
201
+ tickerCounter := time .NewTicker (60 * time .Second )
141
202
defer ticker .Stop ()
203
+ defer tickerCounter .Stop ()
142
204
itemChan := dbQueue .getChan ()
143
205
for {
144
206
select {
145
207
case item := <- itemChan :
146
208
dbStore (item )
147
209
case <- ticker .C :
148
210
log .Debug ("Make clickhouse row" )
149
- dbDoTransfer ()
211
+ dbSaveMetrics ()
212
+ case <- ticker .C :
213
+ log .Debug ("Make counter row" )
214
+ dbProcessEvents ()
150
215
case <- dbShutdownChan :
151
216
log .Debug ("DB shuting down" )
152
- dbDoTransfer ()
217
+ // TODO make it in gorutines/parallel
218
+ dbSaveMetrics ()
219
+ dbProcessEvents ()
153
220
return
154
221
}
155
222
}
0 commit comments