test_transaction_durability.js (5630B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 /* exported testSteps */ 7 async function testSteps() { 8 const name = "test_transaction_durability"; 9 const abc = "abcdefghijklmnopqrstuvwxyz"; 10 const durabilities = ["relaxed", "default", "strict"]; 11 12 // Repeat the measurement 3 times. 13 const measurementCount = 3; 14 15 // The difference between relaxed and default is negligible (especially with 16 // SSDs). 17 const relaxedDefaultDiffPercentage = 1; 18 19 // The difference between default and strict is notable (even with SSDs). 20 const defaultStrictDiffPercentage = 20; 21 22 // Allow some tolerance (to deal with noise). 23 const tolerancePercentage = (function () { 24 if (isInChaosMode()) { 25 return 50; 26 } 27 28 return 30; 29 })(); 30 31 // Adjust the number of transactions, so the test takes roughly same time 32 // across all platforms (including the chaos mode). 33 const transactionCount = (function () { 34 if (isInChaosMode()) { 35 switch (mozinfo.os) { 36 case "linux": 37 return 50; 38 39 case "mac": 40 return 7; 41 42 case "win": 43 return 650; 44 45 case "android": 46 return 1; 47 48 default: 49 return 250; 50 } 51 } 52 53 switch (mozinfo.os) { 54 case "linux": 55 return 275; 56 57 case "mac": 58 return 1150; 59 60 case "win": 61 return 650; 62 63 case "android": 64 return 135; 65 66 default: 67 return 500; 68 } 69 })(); 70 71 // A helper function (could be moved to a common place). 72 function transposeMatrix(matrix) { 73 for (let i = 0; i < matrix.length; i++) { 74 for (let j = 0; j < i; j++) { 75 const tmp = matrix[i][j]; 76 matrix[i][j] = matrix[j][i]; 77 matrix[j][i] = tmp; 78 } 79 } 80 } 81 82 // A helper function (could be moved to a common place). 83 function getMedian(array) { 84 array.sort((a, b) => a - b); 85 86 const middleIndex = Math.floor(array.length / 2); 87 88 if (array.length % 2 === 0) { 89 return (array[middleIndex - 1] + array[middleIndex]) / 2; 90 } 91 92 return array[middleIndex]; 93 } 94 95 // Data generation. 96 async function createDatabase(actualName) { 97 info(`Creating database ${actualName}`); 98 99 const request = indexedDB.open(actualName, 1); 100 101 const event = await expectingUpgrade(request); 102 103 const database = event.target.result; 104 105 database.createObjectStore(name); 106 107 await expectingSuccess(request); 108 109 return database; 110 } 111 112 async function fillDatabase(database, durability) { 113 return new Promise(function (resolve) { 114 const startTime = ChromeUtils.now(); 115 116 info(`Filling database ${database.name} using ${durability} durability`); 117 118 let index = 0; 119 120 function addData() { 121 const transaction = database.transaction(name, "readwrite", { 122 durability, 123 }); 124 125 const objectStore = transaction.objectStore(name); 126 127 objectStore.add(abc, index++); 128 129 transaction.oncomplete = function () { 130 if (index < transactionCount) { 131 addData(); 132 } else { 133 const endTime = ChromeUtils.now(); 134 135 const timeDelta = endTime - startTime; 136 137 info( 138 `Filled database ${database.name} using ${durability} ` + 139 `durability in ${timeDelta} msec` 140 ); 141 142 resolve(timeDelta); 143 } 144 }; 145 } 146 147 addData(); 148 }); 149 } 150 151 const timeDeltaMatrix = await (async function () { 152 let timeDeltaMatrix = []; 153 154 for ( 155 let measurementIndex = 0; 156 measurementIndex < measurementCount; 157 measurementIndex++ 158 ) { 159 let databases = []; 160 161 for ( 162 let durabilityIndex = 0; 163 durabilityIndex < durabilities.length; 164 durabilityIndex++ 165 ) { 166 const actualName = 167 name + "_" + measurementIndex + "_" + durabilityIndex; 168 169 const database = await createDatabase(actualName); 170 171 databases.push(database); 172 } 173 174 let promises = []; 175 176 for ( 177 let durabilityIndex = 0; 178 durabilityIndex < durabilities.length; 179 durabilityIndex++ 180 ) { 181 const promise = fillDatabase( 182 databases[durabilityIndex], 183 durabilities[durabilityIndex] 184 ); 185 186 promises.push(promise); 187 } 188 189 const timeDeltas = await Promise.all(promises); 190 191 timeDeltaMatrix.push(timeDeltas); 192 } 193 194 // Convert rows to columns. 195 transposeMatrix(timeDeltaMatrix); 196 197 return timeDeltaMatrix; 198 })(); 199 200 // Data evaluation. 201 { 202 let lastTimeDeltaMedian; 203 204 for ( 205 let durabilityIndex = 0; 206 durabilityIndex < durabilities.length; 207 durabilityIndex++ 208 ) { 209 const timeDeltaMedian = getMedian(timeDeltaMatrix[durabilityIndex]); 210 211 info("Time delta median: " + timeDeltaMedian); 212 213 if (lastTimeDeltaMedian) { 214 const durability = durabilities[durabilityIndex]; 215 216 const actualTolerancePercentage = 217 tolerancePercentage - 218 (durability == "default" 219 ? relaxedDefaultDiffPercentage 220 : defaultStrictDiffPercentage); 221 222 const coefficient = actualTolerancePercentage / 100; 223 224 const adjustedTimeDeltaMedian = 225 coefficient >= 0 226 ? timeDeltaMedian * (1 + coefficient) 227 : timeDeltaMedian / (1 + Math.abs(coefficient)); 228 229 Assert.greater( 230 adjustedTimeDeltaMedian, 231 lastTimeDeltaMedian, 232 `Database filling using higher (${durability}) durability should ` + 233 `take more time` 234 ); 235 } 236 237 lastTimeDeltaMedian = timeDeltaMedian; 238 } 239 } 240 }