Skip to content

Commit c7c174b

Browse files
authored
Merge pull request #135 from TobiasBengtsson/lock-free-gauge-set
Make updateGauge lock-free in critical paths of APC and APCng
2 parents bf674d5 + 6a4746c commit c7c174b

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

src/Prometheus/Storage/APC.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,32 @@ public function updateSummary(array $data): void
123123
public function updateGauge(array $data): void
124124
{
125125
$valueKey = $this->valueKey($data);
126+
$old = apcu_fetch($valueKey);
126127
if ($data['command'] === Adapter::COMMAND_SET) {
127-
apcu_store($valueKey, $this->toBinaryRepresentationAsInteger($data['value']));
128-
apcu_store($this->metaKey($data), json_encode($this->metaData($data)));
128+
$new = $this->toBinaryRepresentationAsInteger($data['value']);
129+
if ($old === false) {
130+
apcu_store($valueKey, $new);
131+
apcu_store($this->metaKey($data), json_encode($this->metaData($data)));
132+
return;
133+
} else {
134+
// Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91
135+
while (true) {
136+
if ($old !== false) {
137+
if (apcu_cas($valueKey, $old, $new)) {
138+
return;
139+
} else {
140+
$old = apcu_fetch($valueKey);
141+
}
142+
} else {
143+
// Cache got evicted under our feet? Just consider it a fresh/new insert and move on.
144+
apcu_store($valueKey, $new);
145+
apcu_store($this->metaKey($data), json_encode($this->metaData($data)));
146+
return;
147+
}
148+
}
149+
}
129150
} else {
130-
if (!apcu_exists($valueKey)) {
151+
if ($old === false) {
131152
$new = apcu_add($valueKey, $this->toBinaryRepresentationAsInteger(0));
132153
if ($new) {
133154
apcu_store($this->metaKey($data), json_encode($this->metaData($data)));

src/Prometheus/Storage/APCng.php

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,16 +169,34 @@ public function updateSummary(array $data): void
169169
public function updateGauge(array $data): void
170170
{
171171
$valueKey = $this->valueKey($data);
172+
$old = apcu_fetch($valueKey);
172173
if ($data['command'] === Adapter::COMMAND_SET) {
173-
apcu_store($valueKey, $this->convertToIncrementalInteger($data['value']), 0);
174-
$this->storeMetadata($data);
175-
$this->storeLabelKeys($data);
174+
$new = $this->convertToIncrementalInteger($data['value']);
175+
if ($old === false) {
176+
apcu_store($valueKey, $new, 0);
177+
$this->storeMetadata($data);
178+
$this->storeLabelKeys($data);
179+
180+
return;
181+
}
182+
183+
for ($loops = 0; $loops < self::MAX_LOOPS; $loops++) {
184+
if (apcu_cas($valueKey, $old, $new)) {
185+
break;
186+
}
187+
$old = apcu_fetch($valueKey);
188+
if ($old === false) {
189+
apcu_store($valueKey, $new, 0);
190+
$this->storeMetadata($data);
191+
$this->storeLabelKeys($data);
192+
193+
return;
194+
}
195+
}
176196

177197
return;
178198
}
179199

180-
$old = apcu_fetch($valueKey);
181-
182200
if ($old === false) {
183201
apcu_add($valueKey, 0, 0);
184202
$this->storeMetadata($data);
@@ -896,6 +914,10 @@ private function decodeLabelKey(string $str): string
896914
private function storeMetadata(array $data, bool $encoded = true): void
897915
{
898916
$metaKey = $this->metaKey($data);
917+
if (apcu_exists($metaKey)) {
918+
return;
919+
}
920+
899921
$metaData = $this->metaData($data);
900922
$toStore = $metaData;
901923

0 commit comments

Comments
 (0)