зеркало из https://github.com/mozilla/gecko-dev.git
Bug 965319 - Part 1: Wrong quota calculation for network alarms. r=gene, r=jshih
This commit is contained in:
Родитель
e528fdea89
Коммит
aa521c403f
|
@ -16,7 +16,7 @@ Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
|
|||
Cu.importGlobalProperties(["indexedDB"]);
|
||||
|
||||
const DB_NAME = "net_stats";
|
||||
const DB_VERSION = 6;
|
||||
const DB_VERSION = 7;
|
||||
const DEPRECATED_STORE_NAME = "net_stats";
|
||||
const STATS_STORE_NAME = "net_stats_store";
|
||||
const ALARMS_STORE_NAME = "net_alarm";
|
||||
|
@ -213,6 +213,94 @@ NetworkStatsDB.prototype = {
|
|||
if (DEBUG) {
|
||||
debug("Added new key 'serviceType' for version 6");
|
||||
}
|
||||
} else if (currVersion == 6) {
|
||||
// Replace threshold attribute of alarm index by relativeThreshold in alarms DB.
|
||||
// Now alarms are indexed by relativeThreshold, which is the threshold relative
|
||||
// to current system stats.
|
||||
let alarmsStore = aTransaction.objectStore(ALARMS_STORE_NAME);
|
||||
|
||||
// Delete "alarm" index.
|
||||
if (alarmsStore.indexNames.contains("alarm")) {
|
||||
alarmsStore.deleteIndex("alarm");
|
||||
}
|
||||
|
||||
// Create new "alarm" index.
|
||||
alarmsStore.createIndex("alarm", ['networkId','relativeThreshold'], { unique: false });
|
||||
|
||||
// Populate new "alarm" index attributes.
|
||||
alarmsStore.openCursor().onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.value.relativeThreshold = cursor.value.threshold;
|
||||
cursor.value.absoluteThreshold = cursor.value.threshold;
|
||||
delete cursor.value.threshold;
|
||||
|
||||
cursor.update(cursor.value);
|
||||
cursor.continue();
|
||||
}
|
||||
|
||||
// Previous versions save accumulative totalBytes, increasing althought the system
|
||||
// reboots or resets stats. But is necessary to reset the total counters when reset
|
||||
// through 'clearInterfaceStats'.
|
||||
let statsStore = aTransaction.objectStore(STATS_STORE_NAME);
|
||||
let networks = [];
|
||||
// Find networks stored in the database.
|
||||
statsStore.index("network").openKeyCursor(null, "nextunique").onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
networks.push(cursor.key);
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
networks.forEach(function(network) {
|
||||
let lowerFilter = [0, "", network, 0];
|
||||
let upperFilter = [0, "", network, ""];
|
||||
let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
|
||||
|
||||
// Find number of samples for a given network.
|
||||
statsStore.count(range).onsuccess = function(event) {
|
||||
// If there are more samples than the max allowed, there is no way to know
|
||||
// when does reset take place.
|
||||
if (event.target.result >= VALUES_MAX_LENGTH) {
|
||||
return;
|
||||
}
|
||||
|
||||
let last = null;
|
||||
// Reset detected if the first sample totalCounters are different than bytes
|
||||
// counters. If so, the total counters should be recalculated.
|
||||
statsStore.openCursor(range).onsuccess = function(event) {
|
||||
let cursor = event.target.result;
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
if (!last) {
|
||||
if (cursor.value.rxTotalBytes == cursor.value.rxBytes &&
|
||||
cursor.value.txTotalBytes == cursor.value.txBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursor.value.rxTotalBytes = cursor.value.rxBytes;
|
||||
cursor.value.txTotalBytes = cursor.value.txBytes;
|
||||
cursor.update(cursor.value);
|
||||
last = cursor.value;
|
||||
cursor.continue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Recalculate the total counter for last / current sample
|
||||
cursor.value.rxTotalBytes = last.rxTotalBytes + cursor.value.rxBytes;
|
||||
cursor.value.txTotalBytes = last.txTotalBytes + cursor.value.txBytes;
|
||||
cursor.update(cursor.value);
|
||||
last = cursor.value;
|
||||
cursor.continue();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -515,6 +603,8 @@ NetworkStatsDB.prototype = {
|
|||
sample.serviceType = "";
|
||||
sample.rxBytes = 0;
|
||||
sample.txBytes = 0;
|
||||
sample.rxTotalBytes = 0;
|
||||
sample.txTotalBytes = 0;
|
||||
|
||||
self._saveStats(aTxn, aStore, sample);
|
||||
}
|
||||
|
@ -550,24 +640,78 @@ NetworkStatsDB.prototype = {
|
|||
debug("Get current stats for " + JSON.stringify(aNetwork) + " since " + aDate);
|
||||
}
|
||||
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
if (aDate) {
|
||||
this._getCurrentStatsFromDate(network, aDate, aResultCb);
|
||||
return;
|
||||
}
|
||||
|
||||
this._getCurrentStats(network, aResultCb);
|
||||
},
|
||||
|
||||
_getCurrentStats: function _getCurrentStats(aNetwork, aResultCb) {
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) {
|
||||
let request = null;
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
if (aDate) {
|
||||
let start = this.normalizeDate(aDate);
|
||||
let lowerFilter = [0, network, start];
|
||||
let range = this.dbGlobal.IDBKeyRange.lowerBound(lowerFilter, false);
|
||||
request = store.openCursor(range);
|
||||
} else {
|
||||
request = store.index("network").openCursor(network, "prev");
|
||||
}
|
||||
let upperFilter = [0, "", aNetwork, Date.now()];
|
||||
let range = IDBKeyRange.upperBound(upperFilter, false);
|
||||
request = store.openCursor(range, "prev");
|
||||
|
||||
let result = { rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 0, txTotalBytes: 0 };
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
txn.result = null;
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
txn.result = cursor.value;
|
||||
result.rxBytes = result.rxTotalBytes = cursor.value.rxTotalBytes;
|
||||
result.txBytes = result.txTotalBytes = cursor.value.txTotalBytes;
|
||||
}
|
||||
|
||||
txn.result = result;
|
||||
};
|
||||
}.bind(this), aResultCb);
|
||||
},
|
||||
|
||||
_getCurrentStatsFromDate: function _getCurrentStatsFromDate(aNetwork, aDate, aResultCb) {
|
||||
aDate = new Date(aDate);
|
||||
this.dbNewTxn(STATS_STORE_NAME, "readonly", function(txn, store) {
|
||||
let request = null;
|
||||
let start = this.normalizeDate(aDate);
|
||||
let lowerFilter = [0, "", aNetwork, start];
|
||||
let upperFilter = [0, "", aNetwork, Date.now()];
|
||||
|
||||
let range = IDBKeyRange.upperBound(upperFilter, false);
|
||||
|
||||
let result = { rxBytes: 0, txBytes: 0,
|
||||
rxTotalBytes: 0, txTotalBytes: 0 };
|
||||
|
||||
request = store.openCursor(range, "prev");
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
result.rxBytes = result.rxTotalBytes = cursor.value.rxTotalBytes;
|
||||
result.txBytes = result.txTotalBytes = cursor.value.txTotalBytes;
|
||||
}
|
||||
|
||||
let timestamp = cursor.value.timestamp;
|
||||
let range = IDBKeyRange.lowerBound(lowerFilter, false);
|
||||
request = store.openCursor(range);
|
||||
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
let cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor.value.timestamp == timestamp) {
|
||||
// There is one sample only.
|
||||
result.rxBytes = cursor.value.rxBytes;
|
||||
result.txBytes = cursor.value.txBytes;
|
||||
} else {
|
||||
result.rxBytes -= cursor.value.rxTotalBytes;
|
||||
result.txBytes -= cursor.value.txTotalBytes;
|
||||
}
|
||||
}
|
||||
|
||||
txn.result = result;
|
||||
};
|
||||
};
|
||||
}.bind(this), aResultCb);
|
||||
},
|
||||
|
@ -671,7 +815,7 @@ NetworkStatsDB.prototype = {
|
|||
aTxn.result = false;
|
||||
}
|
||||
|
||||
var network = [aNetwork.id, aNetwork.type];
|
||||
let network = [aNetwork.id, aNetwork.type];
|
||||
let request = aStore.index("network").openKeyCursor(IDBKeyRange.only(network));
|
||||
request.onsuccess = function onsuccess(event) {
|
||||
if (event.target.result) {
|
||||
|
@ -717,7 +861,8 @@ NetworkStatsDB.prototype = {
|
|||
|
||||
alarmToRecord: function alarmToRecord(aAlarm) {
|
||||
let record = { networkId: aAlarm.networkId,
|
||||
threshold: aAlarm.threshold,
|
||||
absoluteThreshold: aAlarm.absoluteThreshold,
|
||||
relativeThreshold: aAlarm.relativeThreshold,
|
||||
data: aAlarm.data,
|
||||
manifestURL: aAlarm.manifestURL,
|
||||
pageURL: aAlarm.pageURL };
|
||||
|
@ -731,7 +876,8 @@ NetworkStatsDB.prototype = {
|
|||
|
||||
recordToAlarm: function recordToalarm(aRecord) {
|
||||
let alarm = { networkId: aRecord.networkId,
|
||||
threshold: aRecord.threshold,
|
||||
absoluteThreshold: aRecord.absoluteThreshold,
|
||||
relativeThreshold: aRecord.relativeThreshold,
|
||||
data: aRecord.data,
|
||||
manifestURL: aRecord.manifestURL,
|
||||
pageURL: aRecord.pageURL };
|
||||
|
@ -837,6 +983,7 @@ NetworkStatsDB.prototype = {
|
|||
},
|
||||
|
||||
getAlarms: function getAlarms(aNetworkId, aManifestURL, aResultCb) {
|
||||
let self = this;
|
||||
this.dbNewTxn(ALARMS_STORE_NAME, "readonly", function(txn, store) {
|
||||
if (DEBUG) {
|
||||
debug("Get alarms for " + aManifestURL);
|
||||
|
@ -851,12 +998,7 @@ NetworkStatsDB.prototype = {
|
|||
}
|
||||
|
||||
if (!aNetworkId || cursor.value.networkId == aNetworkId) {
|
||||
let alarm = { id: cursor.value.id,
|
||||
networkId: cursor.value.networkId,
|
||||
threshold: cursor.value.threshold,
|
||||
data: cursor.value.data };
|
||||
|
||||
txn.result.push(alarm);
|
||||
txn.result.push(self.recordToAlarm(cursor.value));
|
||||
}
|
||||
|
||||
cursor.continue();
|
||||
|
|
|
@ -237,6 +237,10 @@ NetworkStatsManager.prototype = {
|
|||
aOptions = Object.create(null);
|
||||
}
|
||||
|
||||
if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date") {
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
let request = this.createRequest();
|
||||
cpmm.sendAsyncMessage("NetworkStats:SetAlarm",
|
||||
{id: this.getRequestId(request),
|
||||
|
|
|
@ -331,10 +331,11 @@ this.NetworkStatsService = {
|
|||
this._networks[netId].status = NETWORK_STATUS_AWAY;
|
||||
this._currentAlarms[netId] = Object.create(null);
|
||||
aCallback(netId);
|
||||
return;
|
||||
}
|
||||
|
||||
aCallback(null);
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
getAvailableNetworks: function getAvailableNetworks(mm, msg) {
|
||||
|
@ -863,7 +864,7 @@ this.NetworkStatsService = {
|
|||
let alarm = result[i];
|
||||
alarms.push({ id: alarm.id,
|
||||
network: self._networks[alarm.networkId].network,
|
||||
threshold: alarm.threshold,
|
||||
threshold: alarm.absoluteThreshold,
|
||||
data: alarm.data });
|
||||
}
|
||||
|
||||
|
@ -931,22 +932,21 @@ this.NetworkStatsService = {
|
|||
let newAlarm = {
|
||||
id: null,
|
||||
networkId: aNetId,
|
||||
threshold: threshold,
|
||||
absoluteThreshold: null,
|
||||
absoluteThreshold: threshold,
|
||||
relativeThreshold: null,
|
||||
startTime: options.startTime,
|
||||
data: options.data,
|
||||
pageURL: options.pageURL,
|
||||
manifestURL: options.manifestURL
|
||||
};
|
||||
|
||||
self._updateThreshold(newAlarm, function onUpdate(error, _threshold) {
|
||||
self._getAlarmQuota(newAlarm, function onUpdate(error, quota) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
{ id: msg.id, error: error, result: null });
|
||||
return;
|
||||
}
|
||||
|
||||
newAlarm.absoluteThreshold = _threshold.absoluteThreshold;
|
||||
self._db.addAlarm(newAlarm, function addSuccessCb(error, newId) {
|
||||
if (error) {
|
||||
mm.sendAsyncMessage("NetworkStats:SetAlarm:Return",
|
||||
|
@ -971,7 +971,7 @@ this.NetworkStatsService = {
|
|||
_setAlarm: function _setAlarm(aAlarm, aCallback) {
|
||||
let currentAlarm = this._currentAlarms[aAlarm.networkId];
|
||||
if ((Object.getOwnPropertyNames(currentAlarm).length !== 0 &&
|
||||
aAlarm.absoluteThreshold > currentAlarm.alarm.absoluteThreshold) ||
|
||||
aAlarm.relativeThreshold > currentAlarm.alarm.relativeThreshold) ||
|
||||
this._networks[aAlarm.networkId].status != NETWORK_STATUS_READY) {
|
||||
aCallback(null, true);
|
||||
return;
|
||||
|
@ -979,7 +979,7 @@ this.NetworkStatsService = {
|
|||
|
||||
let self = this;
|
||||
|
||||
this._updateThreshold(aAlarm, function onUpdate(aError, aThreshold) {
|
||||
this._getAlarmQuota(aAlarm, function onUpdate(aError, aQuota) {
|
||||
if (aError) {
|
||||
aCallback(aError, null);
|
||||
return;
|
||||
|
@ -1001,7 +1001,7 @@ this.NetworkStatsService = {
|
|||
let interfaceName = self._networks[aAlarm.networkId].interfaceName;
|
||||
if (interfaceName) {
|
||||
networkService.setNetworkInterfaceAlarm(interfaceName,
|
||||
aThreshold.systemThreshold,
|
||||
aQuota,
|
||||
callback);
|
||||
return;
|
||||
}
|
||||
|
@ -1010,7 +1010,7 @@ this.NetworkStatsService = {
|
|||
});
|
||||
},
|
||||
|
||||
_updateThreshold: function _updateThreshold(aAlarm, aCallback) {
|
||||
_getAlarmQuota: function _getAlarmQuota(aAlarm, aCallback) {
|
||||
let self = this;
|
||||
this.updateStats(aAlarm.networkId, function onStatsUpdated(aResult, aMessage) {
|
||||
self._db.getCurrentStats(self._networks[aAlarm.networkId].network,
|
||||
|
@ -1023,28 +1023,19 @@ this.NetworkStatsService = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
// There are no stats for the network of the alarm, set them to default 0 in
|
||||
// order to be able to calculate the offset, systemThreshold and
|
||||
// absoluteThreshold.
|
||||
result = { rxTotalBytes: 0, txTotalBytes: 0,
|
||||
rxSystemBytes: 0, txSystemBytes: 0 };
|
||||
}
|
||||
|
||||
let offset = aAlarm.threshold - result.rxTotalBytes - result.txTotalBytes;
|
||||
let quota = aAlarm.absoluteThreshold - result.rxBytes - result.txBytes;
|
||||
|
||||
// Alarm set to a threshold lower than current rx/tx bytes.
|
||||
if (offset <= 0) {
|
||||
if (quota <= 0) {
|
||||
aCallback("InvalidStateError", null);
|
||||
return;
|
||||
}
|
||||
|
||||
let threshold = {
|
||||
systemThreshold: result.rxSystemBytes + result.txSystemBytes + offset,
|
||||
absoluteThreshold: result.rxTotalBytes + result.txTotalBytes + offset
|
||||
};
|
||||
aAlarm.relativeThreshold = aAlarm.startTime
|
||||
? result.rxTotalBytes + result.txTotalBytes + quota
|
||||
: aAlarm.absoluteThreshold;
|
||||
|
||||
aCallback(null, threshold);
|
||||
aCallback(null, quota);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -1096,7 +1087,7 @@ this.NetworkStatsService = {
|
|||
let pageURI = Services.io.newURI(aAlarm.pageURL, null, null);
|
||||
|
||||
let alarm = { "id": aAlarm.id,
|
||||
"threshold": aAlarm.threshold,
|
||||
"threshold": aAlarm.absoluteThreshold,
|
||||
"data": aAlarm.data };
|
||||
messenger.sendMessage("networkstats-alarm", alarm, pageURI, manifestURI);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче