Commit 6467ce58 authored by Nigel Kukard's avatar Nigel Kukard
Browse files

* Fixed race condition affecting quotas and accounting updates

- Robert Anderson <randerson@lbsd.net>
parent 9d07ca69
......@@ -164,8 +164,8 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
if (defined($atrack)) {
# Make sure we have initialized the counters
if (!defined($newCounters{$atrack->{'AccountingID'}})) {
$newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} = $atrack->{'MessageCount'};
$newCounters{$atrack->{'AccountingID'}}->{'MessageCumulativeSize'} = $atrack->{'MessageCumulativeSize'};
$newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} = 0;
$newCounters{$atrack->{'AccountingID'}}->{'MessageCumulativeSize'} = 0;
}
# Check for violation
......@@ -174,13 +174,8 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
if ($accounting->{'MessageCountLimit'} =~ /^[0-9]+$/) {
# Check if we exceeded
if ($accounting->{'MessageCountLimit'} > 0 && (
# Check current counter
(
defined($newCounters{$atrack->{'AccountingID'}}->{'MessageCount'}) &&
$newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} >= $accounting->{'MessageCountLimit'}
) ||
# Or if that doesn't match, the DB counter
$atrack->{'MessageCount'} >= $accounting->{'MessageCountLimit'}
# Check current counter
$atrack->{'MessageCount'} >= $accounting->{'MessageCountLimit'}
)) {
$hasExceeded = "Policy rejection; Message count exceeded";
}
......@@ -208,14 +203,14 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
}
}
}
} else {
$atrack->{'AccountingID'} = $accounting->{'ID'};
$atrack->{'TrackKey'} = $trackKey;
$atrack->{'PeriodKey'} = $periodKey;
$atrack->{'MessageCount'} = 0;
$atrack->{'MessageCumulativeSize'} = 0;
# Make sure we have initialized the counters
if (!defined($newCounters{$atrack->{'AccountingID'}})) {
$newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} = $atrack->{'MessageCount'};
......@@ -257,25 +252,24 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
# Loop with tracking ID's and update
foreach my $atrack (@trackingList) {
# Percent used
my $pCountUsage = $newCounters{$atrack->{'AccountingID'}}->{'MessageCount'};
my $pCumulativeSizeUsage = $newCounters{$atrack->{'AccountingID'}}->{'MessageCumulativeSize'};
my $pCountUsage = "/-";
my $pCumulativeSizeUsage = "/-";
# If we have additional limits, add to the usage string
if (defined($atrack->{'MessageCountLimit'}) && $atrack->{'MessageCountLimit'} > 0) {
$pCountUsage = $newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} + $atrack->{'MessageCount'};
$pCountUsage .= sprintf('/%s (%.1f%%)',
$atrack->{'MessageCountLimit'},
( $newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} / $atrack->{'MessageCountLimit'} ) * 100
( ($newCounters{$atrack->{'AccountingID'}}->{'MessageCount'} + $atrack->{'MessageCount'}) /
$atrack->{'MessageCountLimit'} ) * 100
);
} else {
$pCountUsage .= "/-";
}
if (defined($atrack->{'MessageCumulativeSizeLimit'}) && $atrack->{'MessageCumulativeSizeLimit'} > 0) {
$pCumulativeSizeUsage = $newCounters{$atrack->{'AccountingID'}}->{'MessageCumulativeSize'} + $atrack->{'MessageCumulativeSize'};
$pCumulativeSizeUsage .= sprintf('/%s (%.1f%%)',
$atrack->{'MessageCumulativeSizeLimit'},
( $newCounters{$atrack->{'AccountingID'}}->{'MessageCumulativeSize'} /
( ($newCounters{$atrack->{'AccountingID'}}->{'MessageCumulativeSize'} + $atrack->{'MessageCumulativeSize'}) /
$atrack->{'MessageCumulativeSizeLimit'} ) * 100
);
} else {
$pCumulativeSizeUsage .= "/-";
}
# Update database
......@@ -283,8 +277,8 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
UPDATE
@TP@accounting_tracking
SET
MessageCount = ?,
MessageCumulativeSize = ?,
MessageCount = MessageCount + ?,
MessageCumulativeSize = MessageCumulativeSize + ?,
LastUpdate = ?
WHERE
AccountingID = ?
......@@ -358,13 +352,15 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
# If we have exceeded, set verdict
} else {
# Percent used
my $pCountUsage = $newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCount'};
my $pCumulativeSizeUsage = $newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCumulativeSize'};
my $pCountUsage = $newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCount'} + $exceededAtrack->{'MessageCount'};
my $pCumulativeSizeUsage = $newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCumulativeSize'} +
$exceededAtrack->{'MessageCumulativeSize'};
# If we have additional limits, add to the usage string
if (defined($exceededAtrack->{'MessageCountLimit'}) && $exceededAtrack->{'MessageCountLimit'} > 0) {
$pCountUsage .= sprintf('/%s (%.1f%%)',
$exceededAtrack->{'MessageCountLimit'},
( $newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCount'} / $exceededAtrack->{'MessageCountLimit'} ) * 100
( ($newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCount'} +
$exceededAtrack->{'MessageCount'}) / $exceededAtrack->{'MessageCountLimit'} ) * 100
);
} else {
$pCountUsage .= "/-";
......@@ -372,8 +368,8 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
if (defined($exceededAtrack->{'MessageCumulativeSizeLimit'}) && $exceededAtrack->{'MessageCumulativeSizeLimit'} > 0) {
$pCumulativeSizeUsage .= sprintf('/%s (%.1f%%)',
$exceededAtrack->{'MessageCumulativeSizeLimit'},
( $newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCumulativeSize'} /
$exceededAtrack->{'MessageCumulativeSizeLimit'} ) * 100
( ($newCounters{$exceededAtrack->{'AccountingID'}}->{'MessageCumulativeSize'} +
$exceededAtrack->{'MessageCumulativeSize'}) / $exceededAtrack->{'MessageCumulativeSizeLimit'} ) * 100
);
} else {
$pCumulativeSizeUsage .= "/-";
......@@ -454,21 +450,21 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'_Recipie
}
# Bump up counter
$atrack->{'MessageCumulativeSize'} += ceil($sessionData->{'Size'} / 1024);
my $sessionDataSize = ceil($sessionData->{'Size'} / 1024);
# Update database
my $sth = DBDo('
UPDATE
@TP@accounting_tracking
SET
MessageCumulativeSize = ?,
MessageCumulativeSize = MessageCumulativeSize + ?,
LastUpdate = ?
WHERE
AccountingID = ?
AND TrackKey = ?
AND PeriodKey = ?
',
$atrack->{'MessageCumulativeSize'},$now,$atrack->{'AccountingID'},$atrack->{'TrackKey'},
$sessionDataSize,$now,$atrack->{'AccountingID'},$atrack->{'TrackKey'},
$atrack->{'PeriodKey'}
);
if (!$sth) {
......
......@@ -169,17 +169,19 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
my $elapsedTime = defined($qtrack->{'LastUpdate'}) ? ( $now - $qtrack->{'LastUpdate'} ) : $quota->{'Period'};
# Check if elapsedTime is longer than period, or negative (time diff between servers?)
my $currentCounter;
if ($elapsedTime > $quota->{'Period'} || $elapsedTime < 0) {
$qtrack->{'Counter'} = 0;
# Calculate the % of the period we have, and multiply it with the counter ... this should give us a reasonably
# accurate counting
} else {
$qtrack->{'Counter'} = ( 1 - ($elapsedTime / $quota->{'Period'}) ) * $qtrack->{'Counter'};
$currentCounter = ( 1 - ($elapsedTime / $quota->{'Period'}) ) * $qtrack->{'Counter'};
}
# Make sure increment is at least 0
$newCounters{$qtrack->{'QuotasLimitsID'}} = $qtrack->{'Counter'}
$newCounters{$qtrack->{'QuotasLimitsID'}} = defined($currentCounter) ?
$qtrack->{'Counter'} - $currentCounter : $qtrack->{'Counter'}
if (!defined($newCounters{$qtrack->{'QuotasLimitsID'}}));
# Limit type
......@@ -206,6 +208,7 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
$qtrack->{'QuotasLimitsID'} = $limit->{'ID'};
$qtrack->{'TrackKey'} = $key;
$qtrack->{'Counter'} = 0;
$qtrack->{'LastUpdate'} = $now;
# Make sure increment is at least 0
$newCounters{$qtrack->{'QuotasLimitsID'}} = $qtrack->{'Counter'}
......@@ -253,14 +256,14 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
foreach my $qtrack (@trackingList) {
# Percent used
my $pused = sprintf('%.1f', ( $newCounters{$qtrack->{'QuotasLimitsID'}} / $qtrack->{'CounterLimit'} ) * 100);
my $pused = sprintf('%.1f', ( ($newCounters{$qtrack->{'QuotasLimitsID'}} + $qtrack->{'QuotasLimitsID'}) / $qtrack->{'CounterLimit'} ) * 100);
# Update database
my $sth = DBDo('
UPDATE
@TP@quotas_tracking
SET
Counter = ?,
Counter = Counter + ?,
LastUpdate = ?
WHERE
QuotasLimitsID = ?
......@@ -301,7 +304,7 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
$qtrack->{'LimitID'},
$qtrack->{'DBKey'},
$qtrack->{'LimitType'},
sprintf('%.0f',$newCounters{$qtrack->{'QuotasLimitsID'}}),
sprintf('%.0f',$newCounters{$qtrack->{'QuotasLimitsID'}} + $qtrack->{'QuotasLimitsID'}),
$qtrack->{'CounterLimit'},
$pused);
......@@ -320,7 +323,7 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
$qtrack->{'LimitID'},
$qtrack->{'DBKey'},
$qtrack->{'LimitType'},
sprintf('%.0f',$newCounters{$qtrack->{'QuotasLimitsID'}}),
sprintf('%.0f',$newCounters{$qtrack->{'QuotasLimitsID'}} + $qtrack->{'QuotasLimitsID'}),
$qtrack->{'CounterLimit'},
$pused);
......@@ -334,7 +337,7 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
# If we have exceeded, set verdict
} else {
# Percent used
my $pused = sprintf('%.1f', ( $newCounters{$exceededQtrack->{'QuotasLimitsID'}} / $exceededQtrack->{'CounterLimit'} ) * 100);
my $pused = sprintf('%.1f', ( ($newCounters{$exceededQtrack->{'QuotasLimitsID'}} + $exceededQtrack->{'QuotasLimitsID'}) / $exceededQtrack->{'CounterLimit'} ) * 100);
# Log rejection to mail log
$server->maillog("module=Quotas, action=%s, host=%s, helo=%s, from=%s, to=%s, reason=quota_match, policy=%s, quota=%s, limit=%s, track=%s, "
......@@ -349,7 +352,7 @@ POLICY: foreach my $priority (sort {$a <=> $b} keys %{$sessionData->{'Policy'}}
$exceededQtrack->{'LimitID'},
$exceededQtrack->{'DBKey'},
$exceededQtrack->{'LimitType'},
sprintf('%.0f',$newCounters{$exceededQtrack->{'QuotasLimitsID'}}),
sprintf('%.0f',$newCounters{$exceededQtrack->{'QuotasLimitsID'}} + $exceededQtrack->{'QuotasLimitsID'}),
$exceededQtrack->{'CounterLimit'},
$pused);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment