tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }