github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/api/ui/debug/js/backfill.js (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 var upsertbatchTable; 16 17 function initSchedulerViewer() { 18 // Disable null value warning from data table. 19 $.fn.dataTable.ext.errMode = 'none'; 20 21 $.ajax({ 22 url: "/dbg/jobs/backfill", 23 success: function (body) { 24 var runningJobData = [] 25 var pastRunsData = [] 26 for (var key in body) { 27 var strs = key.split("|") 28 var row = body[key] 29 row['table'] = strs[0] 30 row['shard'] = strs[1] 31 row['type'] = strs[2] 32 if ('lastDuration' in row) { 33 row['lastDuration'] = row['lastDuration'].toDuration() 34 } 35 36 if ('lockDuration' in row) { 37 row['lockDuration'] = row['lockDuration'].toDuration() 38 } 39 40 if (row['status'] == 'running') { 41 runningJobData.push(row) 42 } else { 43 // Also get stats like current backfill buffer size and backfilling size, etc. 44 $.ajax({ 45 url: "/dbg/{0}/{1}".format(row['table'], row['shard']), 46 success: function (body) { 47 var backfillMgr = body["liveStore"]["backfillManager"]; 48 if (backfillMgr) { 49 row["numRecords"] = backfillMgr["numRecords"]; 50 row["currentBufferSize"] = backfillMgr["currentBufferSize"]; 51 row["backfillingBufferSize"] = backfillMgr["backfillingBufferSize"]; 52 row["maxBufferSize"] = backfillMgr["maxBufferSize"]; 53 row["numUpsertBatches"] = backfillMgr["numUpsertBatches"]; 54 } 55 }, 56 error: function (xhr) { 57 alert(xhr.responseText); 58 }, 59 async: false 60 } 61 ) 62 pastRunsData.push(row); 63 } 64 } 65 initRunningJobTable(runningJobData) 66 initPastRunTable(pastRunsData) 67 }, 68 error: function (xhr) { 69 alert(xhr.responseText) 70 } 71 } 72 ); 73 74 // Init table selector. 75 $('#table-selector').select2({ 76 ajax: { 77 url: "/schema/tables", 78 dataType: 'json', 79 quietMillis: 50, 80 processResults: function (data) { 81 return { 82 results: $.map(data, function (item, idx) { 83 return { 84 text: item, 85 id: idx + 1, 86 } 87 }) 88 }; 89 } 90 }, 91 width: 'resolve' 92 }).on('change', function () { 93 refreshBackfillQueue(); 94 }); 95 96 // Init shard selector. 97 $('#shard-selector').select2({ 98 data: [ 99 { 100 "id": 0, 101 "text": 0, 102 } 103 ] 104 }).on('change', function (e) { 105 refreshBackfillQueue(); 106 }); 107 } 108 109 function refreshBackfillQueue() { 110 var table = $('#table-selector').select2('data')[0].text; 111 var shard = $('#shard-selector').select2('data')[0].text; 112 if ($('#upsertbatch-selector').select2()) { 113 $('#upsertbatch-selector').empty(); 114 $('#upsertbatch-selector').select2("destroy"); 115 } 116 117 $('#upsertbatch-selector').select2({ 118 ajax: { 119 url: "/dbg/{0}/{1}".format(table, shard), 120 cache: true, 121 dataType: 'json', 122 quietMillis: 50, 123 processResults: function (data) { 124 var results = []; 125 var numUpsertBatches = data.liveStore.backfillManager.numUpsertBatches; 126 for (var i = 0; i < numUpsertBatches; i++) { 127 results.push({ 128 text: i, 129 id: i + 1 130 }); 131 } 132 133 return { 134 results: results 135 }; 136 } 137 }, 138 width: '100px', 139 minimumResultsForSearch: -1 140 }).on('change', function (e) { 141 refreshUpsertBatchTable(); 142 }); 143 } 144 145 function refreshUpsertBatchTable() { 146 var table = $("#table-selector").select2('data')[0].text; 147 var shard = $("#shard-selector").select2('data')[0].text; 148 var upsertBatch = $("#upsertbatch-selector").select2('data')[0].text; 149 150 $.ajax({ 151 url: "/dbg/{0}/{1}/backfill-manager/upsertbatches/{2}".format(table, shard, upsertBatch), 152 success: function (body) { 153 var columns = body.columnNames.map(function (name) { 154 return {"title": name} 155 } 156 ); 157 158 // Need to explicitly destroy old data table. 159 if (upsertbatchTable) { 160 upsertbatchTable.destroy(); 161 $('#upsertbatch-table').empty(); 162 } 163 164 upsertbatchTable = $('#upsertbatch-table').DataTable({ 165 "serverSide": true, 166 "processing": true, 167 "paging": true, 168 "searching": false, 169 "pageLength": 20, 170 "lengthMenu": [[1, 10, 25, 50, 100], [1, 10, 25, 50, 100]], 171 "columns": columns, 172 "ajax": { 173 "type": "GET", 174 "url": "/dbg/{0}/{1}/backfill-manager/upsertbatches/{2}".format(table, shard, upsertBatch), 175 "dataType": "json", 176 "contentType": 'application/json' 177 } 178 }); 179 }, 180 error: function (error) { 181 alert('error: ' + eval(error)); 182 } 183 }); 184 } 185 186 function submitBackfillJob(table, shard) { 187 var url = "/dbg/{0}/{1}/backfill".format(table, shard) 188 $.ajax({ 189 url: url, 190 method: "POST", 191 dataType: 'json', 192 success: function (body) { 193 alert(body); 194 reloadCurrentTab(); 195 }, 196 error: function (xhr) { 197 alert(xhr.responseText); 198 } 199 } 200 ) 201 } 202 203 function initRunningJobTable(data) { 204 $('#running-job-table').DataTable({ 205 paging: false, 206 searching: false, 207 aoColumns: [ 208 {title: "Table", data: "table"}, 209 {title: "Shard", data: "shard", type: "num"}, 210 {title: "Type", data: "type"}, 211 {title: "Stage", data: "stage"}, 212 {title: "Current", data: "current", type: "num"}, 213 {title: "Total", data: "total", type: "num"}, 214 ], 215 aaData: data, 216 }); 217 } 218 219 function initPastRunTable(data) { 220 $('#past-runs-table').DataTable({ 221 paging: true, 222 searching: true, 223 pageLength: 20, 224 lengthMenu: [[1, 10, 25, 50, 100], [1, 10, 25, 50, 100]], 225 aoColumns: [ 226 {title: "Table", data: "table"}, 227 {title: "Shard", data: "shard", type: "num"}, 228 {title: "Type", data: "type"}, 229 {title: "Status", data: "status"}, 230 {title: "Number of Records Backfilled", data: "numRecords", type: "num"}, 231 {title: "Number of Affected Days", data: "numAffectedDays", type: "num"}, 232 { 233 title: "Action", 234 mData: null, 235 bSortable: false, 236 mRender: function (data, type, row) { 237 var table = row['table'] 238 var shard = row['shard'] 239 return $("<div />").append($( 240 "<button class='ui-button' onclick=\"submitBackfillJob('" + table + "'," + shard + ")\">Backfill</button>")).html(); 241 }, 242 }, 243 { 244 title: "Last Error", 245 data: "lastError", 246 type: "string", 247 render: function (data) { 248 return JSON.stringify(data) 249 } 250 }, 251 { 252 title: "Last Start Time", 253 data: "lastStartTime", 254 type: "date", 255 render: function (data) { 256 return new Date(data).toLocaleString() 257 } 258 }, 259 {title: "Last Duration", data: "lastDuration", type: "string"}, 260 {title: "Last Lock Wait Duration", data: "lockDuration", type: "string"}, 261 {title: "Redo Log File", data: "redologFile", type: "number"}, 262 {title: "Batch Offset", data: "batchOffset", type: "number"}, 263 {title: "Number of Records in Queue", data: "numRecords", type: "number"}, 264 {title: "Current Buffer Size", data: "currentBufferSize", type: "number"}, 265 {title: "Backfilling Buffer Size", data: "backfillingBufferSize", type: "number"}, 266 {title: "Max Buffer Size", data: "maxBufferSize", type: "number"}, 267 {title: "Num Upsert Batches", data: "numUpsertBatches", type: "number"}, 268 ], 269 aaData: data, 270 }); 271 }