github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/query/device_manager_test.go (about) 1 // Copyright (c) 2017-2018 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package query 16 17 import ( 18 "github.com/onsi/ginkgo" 19 . "github.com/onsi/gomega" 20 "github.com/uber/aresdb/memstore" 21 "github.com/uber/aresdb/query/common" 22 "github.com/uber/aresdb/query/expr" 23 "github.com/uber/aresdb/utils" 24 "sync" 25 "time" 26 ) 27 28 var _ = ginkgo.Describe("device_manager", func() { 29 var deviceManager *DeviceManager 30 var leastMemStrategy deviceChooseStrategy 31 freeMemory := []int{400, 2000, 3000} 32 queryCounts := []int{1, 1, 0} 33 deviceCount := 3 34 35 ginkgo.BeforeEach(func() { 36 // create DeviceInfoMap 37 deviceInfoArray := make([]*DeviceInfo, deviceCount) 38 for device := 0; device < deviceCount; device++ { 39 deviceInfo := DeviceInfo{ 40 DeviceID: device, 41 QueryCount: queryCounts[device], 42 TotalAvailableMemory: 3000, 43 FreeMemory: freeMemory[device], 44 QueryMemoryUsageMap: make(map[*AQLQuery]int, 0), 45 } 46 deviceInfoArray[device] = &deviceInfo 47 } 48 49 deviceManager = &DeviceManager{ 50 RWMutex: &sync.RWMutex{}, 51 DeviceInfos: deviceInfoArray, 52 Timeout: 5, 53 MaxAvailableMemory: 3000, 54 } 55 56 deviceManager.deviceAvailable = sync.NewCond(deviceManager) 57 leastMemStrategy = leastQueryCountAndMemoryStrategy{ 58 deviceManager: deviceManager, 59 } 60 }) 61 62 ginkgo.AfterEach(func() { 63 utils.ResetClockImplementation() 64 }) 65 66 ginkgo.It("leastMemStrategy should work", func() { 67 deviceManager.strategy = leastMemStrategy 68 queries := [5]*AQLQuery{{}, {}, {}, {}} 69 devices := [5]int{} 70 // case 1: w/o device hint, return the device w/ least query count. 71 devices[0] = deviceManager.findDevice(queries[0], 1000, -1) 72 Ω(devices[0]).Should(Equal(2)) 73 // 400 2000 2000 74 // 1 1 1 75 76 // case 2: w/ device hint, return the device if it meets the requirement 77 devices[1] = deviceManager.findDevice(queries[1], 1000, 2) 78 Ω(devices[1]).Should(Equal(2)) 79 // 400 2000 1000 80 // 1 1 2 81 82 // case 3: w/ device hint, but cannot meet the requirements 83 devices[2] = deviceManager.findDevice(queries[2], 1500, 0) 84 Ω(devices[2]).Should(Equal(1)) 85 // 400 500 1000 86 // 1 2 2 87 88 // case 4: unable to find a device that meets the requirement 89 devices[3] = deviceManager.findDevice(queries[3], 2000, 0) 90 Ω(devices[3]).Should(Equal(-1)) 91 // 400 500 1000 92 // 1 2 2 93 94 // case 5: return device with least query count and least available memory. 95 devices[4] = deviceManager.findDevice(queries[4], 500, 0) 96 Ω(devices[4]).Should(Equal(1)) 97 // 400 0 1000 98 // 1 3 2 99 100 Ω(deviceManager.DeviceInfos[0].FreeMemory).Should(BeEquivalentTo(400)) 101 Ω(deviceManager.DeviceInfos[1].FreeMemory).Should(BeEquivalentTo(0)) 102 Ω(deviceManager.DeviceInfos[2].FreeMemory).Should(BeEquivalentTo(1000)) 103 104 Ω(deviceManager.DeviceInfos[0].QueryCount).Should(BeEquivalentTo(1)) 105 Ω(deviceManager.DeviceInfos[1].QueryCount).Should(BeEquivalentTo(3)) 106 Ω(deviceManager.DeviceInfos[2].QueryCount).Should(BeEquivalentTo(2)) 107 108 for i := range devices { 109 deviceManager.ReleaseReservedMemory(devices[i], queries[i]) 110 } 111 112 for device, deviceInfo := range deviceManager.DeviceInfos { 113 Ω(deviceInfo.FreeMemory).Should(Equal(freeMemory[device])) 114 Ω(deviceInfo.QueryCount).Should(Equal(queryCounts[device])) 115 Ω(deviceInfo.QueryMemoryUsageMap).Should(BeEmpty()) 116 } 117 }) 118 119 ginkgo.It("query queuing should work", func() { 120 deviceManager = &DeviceManager{ 121 RWMutex: &sync.RWMutex{}, 122 DeviceInfos: []*DeviceInfo{ 123 { 124 DeviceID: 0, 125 QueryCount: 0, 126 TotalAvailableMemory: 1000, 127 FreeMemory: 500, 128 QueryMemoryUsageMap: make(map[*AQLQuery]int, 0), 129 }, 130 }, 131 Timeout: 5, 132 MaxAvailableMemory: 1000, 133 } 134 135 leastQueryCountAndMemStrategy := leastQueryCountAndMemoryStrategy{ 136 deviceManager: deviceManager, 137 } 138 139 deviceManager.strategy = leastQueryCountAndMemStrategy 140 deviceManager.deviceAvailable = sync.NewCond(deviceManager) 141 142 queries := [3]*AQLQuery{{}, {}, {}} 143 devices := [4]int{} 144 timeout := 3 145 146 utils.SetCurrentTime(time.Unix(0, 0)) 147 148 // first assign 500 bytes to a query 1. 149 devices[0] = deviceManager.FindDevice(queries[0], 500, -1, timeout) 150 Ω(devices[0]).Should(Equal(0)) 151 Ω(deviceManager.DeviceInfos[0].FreeMemory).Should(Equal(0)) 152 153 wg := sync.WaitGroup{} 154 wg.Add(2) 155 // query 2: 156 // requires 500 bytes, needs to wait for release of query 1. 157 go func() { 158 defer wg.Done() 159 devices[1] = deviceManager.FindDevice(queries[1], 500, -1, timeout) 160 deviceManager.ReleaseReservedMemory(devices[1], queries[1]) 161 }() 162 163 // query 3: 164 // requires 1000 bytes, will timeout. 165 go func() { 166 defer wg.Done() 167 devices[2] = deviceManager.FindDevice(queries[2], 1000, -1, timeout) 168 deviceManager.ReleaseReservedMemory(devices[2], queries[2]) 169 }() 170 171 <-time.NewTimer(time.Second).C 172 // trigger broadcast, query 1 should finish now. 173 deviceManager.ReleaseReservedMemory(devices[0], queries[0]) 174 175 <-time.NewTimer(time.Second).C 176 utils.SetCurrentTime(time.Unix(10, 0)) 177 // trigger another broadcast, query 2 will timeout. 178 device := deviceManager.FindDevice(queries[0], 500, -1, timeout) 179 Ω(device).Should(Equal(0)) 180 deviceManager.ReleaseReservedMemory(device, queries[0]) 181 182 // wait for two go routines. 183 wg.Wait() 184 Ω(deviceManager.DeviceInfos[0].FreeMemory).Should(Equal(500)) 185 Ω(devices[1]).Should(Equal(0)) 186 Ω(devices[2]).Should(Equal(-1)) 187 // query 4: 188 // requi0res 2000 bytes, exceeds max device memory. 189 device = deviceManager.FindDevice(queries[2], 2000, -1, timeout) 190 Ω(device).Should(Equal(-1)) 191 }) 192 193 ginkgo.It("estimate memory usage", func() { 194 testFactory := memstore.TestFactoryT{ 195 RootPath: "../testing/data", 196 FileSystem: utils.OSFileSystem{}, 197 } 198 batch110, err := testFactory.ReadLiveBatch("archiving/batch-110") 199 Ω(err).Should(BeNil()) 200 liveBatch := &memstore.LiveBatch{ 201 Capacity: 5, 202 Batch: memstore.Batch{ 203 RWMutex: &sync.RWMutex{}, 204 Columns: batch110.Columns, 205 }, 206 } 207 208 batchArchive0, err := testFactory.ReadArchiveBatch("archiving/archiveBatch0") 209 Ω(err).Should(BeNil()) 210 archiveBatch := &memstore.ArchiveBatch{ 211 Batch: memstore.Batch{ 212 RWMutex: &sync.RWMutex{}, 213 Columns: batchArchive0.Columns, 214 }, 215 Size: 5, 216 } 217 218 qc := AQLQueryContext{ 219 TableScanners: []*TableScanner{ 220 { 221 Columns: []int{0, 2, 1}, 222 ColumnUsages: map[int]columnUsage{ 223 0: columnUsedByAllBatches, 224 1: columnUsedByAllBatches | columnUsedByPrefilter, 225 2: columnUsedByAllBatches, 226 }, 227 EqualityPrefilterValues: []uint32{1}, 228 }, 229 }, 230 OOPK: OOPKContext{ 231 NumDimsPerDimWidth: common.DimCountsPerDimWidth{0, 0, 1, 0, 0}, 232 DimRowBytes: 5, 233 MeasureBytes: 4, 234 foreignTables: []*foreignTable{{}}, 235 MainTableCommonFilters: []expr.Expr{ 236 &expr.BinaryExpr{ 237 Op: expr.OR, 238 LHS: &expr.BinaryExpr{ 239 Op: expr.EQ, 240 LHS: &expr.UnaryExpr{ 241 Op: expr.UNARY_MINUS, 242 Expr: &expr.VarRef{ 243 Val: "vp1", 244 ColumnID: 1, 245 }, 246 }, 247 RHS: &expr.NumberLiteral{ 248 Val: 0, 249 Int: -2, 250 ExprType: expr.Signed, 251 }, 252 }, 253 RHS: &expr.BinaryExpr{ 254 Op: expr.GTE, 255 LHS: &expr.VarRef{ 256 Val: "vp2", 257 ColumnID: 2, 258 }, 259 RHS: &expr.NumberLiteral{ 260 Val: 0, 261 Int: 2, 262 ExprType: expr.Unsigned, 263 }, 264 }, 265 }, 266 }, 267 Dimensions: []expr.Expr{ 268 &expr.BinaryExpr{ 269 Op: expr.DIV, 270 LHS: &expr.VarRef{ 271 Val: "vp2", 272 ColumnID: 2, 273 }, 274 RHS: &expr.NumberLiteral{ 275 Val: 2, 276 Int: 2, 277 Expr: "2", 278 ExprType: expr.Signed, 279 }, 280 ExprType: expr.Signed, 281 }, 282 }, 283 Measure: &expr.BinaryExpr{ 284 Op: expr.DIV, 285 LHS: &expr.VarRef{ 286 Val: "vp2", 287 ColumnID: 2, 288 }, 289 RHS: &expr.NumberLiteral{ 290 Val: 2, 291 Int: 2, 292 Expr: "2", 293 ExprType: expr.Signed, 294 }, 295 }, 296 }, 297 } 298 299 // expression 300 memUsage := qc.estimateExpressionEvaluationMemUsage(20) 301 Ω(memUsage).Should(Equal(20 * 5 * 2)) 302 303 // sort reduce 304 memUsage = estimateSortReduceMemUsage(20) 305 Ω(memUsage).Should(Equal(720)) 306 307 // batch processing 308 memUsage = qc.estimateMemUsageForBatch(20, 128+128+128) 309 Ω(memUsage).Should(Equal(1204)) 310 311 // live batch columns + processing 312 memUsage = qc.estimateLiveBatchMemoryUsage(liveBatch) 313 Ω(memUsage).Should(Equal(589)) 314 315 // archive batch columns + processing 316 memUsage = qc.estimateArchiveBatchMemoryUsage(archiveBatch, false) 317 Ω(memUsage).Should(Equal(489)) 318 }) 319 })