Skip to content

Commit 2d98323

Browse files
committed
[dns] Refactor cache to cache many records of the same identity with different values
It now returns a manufactured response object
1 parent b25a5c2 commit 2d98323

5 files changed

Lines changed: 91 additions & 16 deletions

File tree

Query/CachedExecutor.php

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace React\Dns\Query;
44

55
use React\Dns\Model\Message;
6+
use React\Dns\Model\Record;
67

78
class CachedExecutor implements ExecutorInterface
89
{
@@ -17,16 +18,43 @@ public function __construct(ExecutorInterface $executor, RecordCache $cache)
1718

1819
public function query($nameserver, Query $query, $callback)
1920
{
20-
$cachedRecord = $this->cache->lookup($query);
21-
if (null !== $cachedRecord) {
22-
$callback($cachedRecord);
21+
$cachedRecords = $this->cache->lookup($query);
22+
if (count($cachedRecords)) {
23+
$cachedResponse = $this->buildResponse($query, $cachedRecords);
24+
$callback($cachedResponse);
2325
return;
2426
}
2527

2628
$cache = $this->cache;
2729
$this->executor->query($nameserver, $query, function ($response) use ($cache, $query, $callback) {
2830
$callback($response);
29-
$cache->storeResponseMessage($response);
31+
$cache->storeResponseMessage($query->currentTime, $response);
3032
});
3133
}
34+
35+
private function buildResponse(Query $query, array $cachedRecords)
36+
{
37+
$response = new Message();
38+
39+
$response->header->set('id', $this->generateId());
40+
$response->header->set('qr', 1);
41+
$response->header->set('opcode', Message::OPCODE_QUERY);
42+
$response->header->set('rd', 1);
43+
$response->header->set('rcode', Message::RCODE_OK);
44+
45+
$response->questions[] = new Record($query->name, $query->type, $query->class);
46+
47+
foreach ($cachedRecords as $record) {
48+
$response->answers[] = $record;
49+
}
50+
51+
$response->prepare();
52+
53+
return $response;
54+
}
55+
56+
protected function generateId()
57+
{
58+
return mt_rand(0, 0xffff);
59+
}
3260
}

Query/Query.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ class Query
77
public $name;
88
public $type;
99
public $class;
10+
public $currentTime;
1011

11-
public function __construct($name, $type, $class)
12+
public function __construct($name, $type, $class, $currentTime)
1213
{
1314
$this->name = $name;
1415
$this->type = $type;
1516
$this->class = $class;
17+
$this->currentTime = $currentTime;
1618
}
1719
}

Query/RecordBag.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace React\Dns\Query;
4+
5+
use React\Dns\Model\Message;
6+
use React\Dns\Model\Record;
7+
8+
class RecordBag
9+
{
10+
private $records = array();
11+
12+
public function set($currentTime, Record $record)
13+
{
14+
$this->records[$record->data] = array($currentTime + $record->ttl, $record);
15+
}
16+
17+
public function all()
18+
{
19+
return array_values(array_map(
20+
function ($value) {
21+
list($expiresAt, $record) = $value;
22+
return $record;
23+
},
24+
$this->records
25+
));
26+
}
27+
28+
public function expire($currentTime)
29+
{
30+
foreach ($this->records as $key => $value) {
31+
list($expiresAt, $record) = $value;
32+
if ($expiresAt <= $currentTime) {
33+
unset($this->records[$key]);
34+
}
35+
}
36+
}
37+
}

Query/RecordCache.php

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,39 @@ class RecordCache
1111

1212
public function lookup(Query $query)
1313
{
14-
$id = $this->serializeQuery($query);
15-
$record = isset($this->records[$id]) ? $this->records[$id] : null;
14+
$id = $this->serializeQueryToIdentity($query);
15+
$records = isset($this->records[$id]) ? $this->records[$id]->all() : array();
1616

17-
return $record;
17+
return $records;
1818
}
1919

20-
public function storeResponseMessage(Message $message)
20+
public function storeResponseMessage($currentTime, Message $message)
2121
{
2222
foreach ($message->answers as $record) {
23-
$this->storeRecord($record);
23+
$this->storeRecord($currentTime, $record);
2424
}
2525
}
2626

27-
public function storeRecord(Record $record)
27+
public function storeRecord($currentTime, Record $record)
2828
{
29-
$id = $this->serializeRecord($record);
30-
$this->records[$id] = $record;
29+
$id = $this->serializeRecordToIdentity($record);
30+
$this->records[$id] = isset($this->records[$id]) ? $this->records[$id] : new RecordBag();
31+
$this->records[$id]->set($currentTime, $record);
3132
}
3233

33-
public function serializeQuery(Query $query)
34+
public function expire($currentTime)
35+
{
36+
foreach ($records as $recordBag) {
37+
$recordBag->expire($currentTime);
38+
}
39+
}
40+
41+
public function serializeQueryToIdentity(Query $query)
3442
{
3543
return sprintf('%s:%s:%s', $query->name, $query->type, $query->class);
3644
}
3745

38-
public function serializeRecord(Record $record)
46+
public function serializeRecordToIdentity(Record $record)
3947
{
4048
return sprintf('%s:%s:%s', $record->name, $record->type, $record->class);
4149
}

Resolver/Resolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function resolve($domain, $callback, $errback = null)
2727
{
2828
$that = $this;
2929

30-
$query = new Query($domain, Message::TYPE_A, Message::CLASS_IN);
30+
$query = new Query($domain, Message::TYPE_A, Message::CLASS_IN, time());
3131

3232
$this->executor->query($this->nameserver, $query, function (Message $response) use ($that, $callback, $errback) {
3333
try {

0 commit comments

Comments
 (0)