Skip to content

Commit fd79ca6

Browse files
bneradtbneradt
authored andcommitted
Timing fix for HostDB restructure (#34)
The default duration of time_since_epoch() is std::chrono::high_resolution_clock::duration, which will not generally be seconds. hostDB.refcountcache->put expects the epoch count to be a number of seconds. This explicitly casts to seconds so we get that expected value. This also makes some other std::chrono time updates. Co-authored-by: bneradt <bneradt@yahooinc.com>
1 parent 7855d2a commit fd79ca6

File tree

3 files changed

+78
-43
lines changed

3 files changed

+78
-43
lines changed

include/tscore/ink_time.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ using ts_hr_time = ts_hr_clock::time_point;
5353

5454
using ts_seconds = std::chrono::seconds;
5555
using ts_milliseconds = std::chrono::milliseconds;
56+
using ts_nanoseconds = std::chrono::nanoseconds;
5657

5758
/// Equivalent of 0 for @c ts_time. This should be used as the default initializer.
5859
static constexpr ts_time TS_TIME_ZERO;

iocore/hostdb/HostDB.cc

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <http/HttpConfig.h>
3939

4040
using ts::TextView;
41+
using std::chrono::duration_cast;
4142

4243
HostDBProcessor hostDBProcessor;
4344
int HostDBProcessor::hostdb_strict_round_robin = 0;
@@ -54,11 +55,12 @@ unsigned int hostdb_ip_stale_interval = HOST_DB_IP_STALE;
5455
unsigned int hostdb_ip_timeout_interval = HOST_DB_IP_TIMEOUT;
5556
unsigned int hostdb_ip_fail_timeout_interval = HOST_DB_IP_FAIL_TIMEOUT;
5657
unsigned int hostdb_serve_stale_but_revalidate = 0;
57-
ts_seconds hostdb_hostfile_check_interval{std::chrono::hours(24)};
58-
// Epoch timestamp of the current hosts file check.
59-
ts_time hostdb_current_interval{TS_TIME_ZERO};
58+
static ts_seconds hostdb_hostfile_check_interval{std::chrono::hours(24)};
59+
// Epoch timestamp of the current hosts file check. This also functions as a
60+
// cached version of ts_clock::now().
61+
ts_time hostdb_current_timestamp{TS_TIME_ZERO};
6062
// Epoch timestamp of the last time we actually checked for a hosts file update.
61-
static ts_time hostdb_last_interval{TS_TIME_ZERO};
63+
static ts_time hostdb_last_timestamp{TS_TIME_ZERO};
6264
// Epoch timestamp when we updated the hosts file last.
6365
static ts_time hostdb_hostfile_update_timestamp{TS_TIME_ZERO};
6466
static char hostdb_filename[PATH_NAME_MAX] = DEFAULT_HOST_DB_FILENAME;
@@ -420,7 +422,7 @@ HostDBBackgroundTask::wait_event(int, void *)
420422

421423
SET_HANDLER(&HostDBBackgroundTask::sync_event);
422424
if (next_sync > ts_milliseconds{100}) {
423-
eventProcessor.schedule_in(this, std::chrono::duration_cast<std::chrono::nanoseconds>(next_sync).count(), ET_TASK);
425+
eventProcessor.schedule_in(this, duration_cast<ts_nanoseconds>(next_sync).count(), ET_TASK);
424426
} else {
425427
eventProcessor.schedule_imm(this, ET_TASK);
426428
}
@@ -552,9 +554,10 @@ HostDBProcessor::start(int, size_t)
552554
REC_EstablishStaticConfigInt32U(hostdb_round_robin_max_count, "proxy.config.hostdb.round_robin_max_count");
553555

554556
//
555-
// Set up hostdb_current_interval
557+
// Initialize hostdb_current_timestamp which is our cached version of
558+
// ts_clock::now().
556559
//
557-
hostdb_current_interval = ts_clock::now();
560+
hostdb_current_timestamp = ts_clock::now();
558561

559562
HostDBContinuation *b = hostDBContAllocator.alloc();
560563
SET_CONTINUATION_HANDLER(b, (HostDBContHandler)&HostDBContinuation::backgroundEvent);
@@ -693,19 +696,19 @@ probe(const Ptr<ProxyMutex> &mutex, HostDBHash const &hash, bool ignore_timeout)
693696
}
694697

695698
// If the record is stale, but we want to revalidate-- lets start that up
696-
if ((!ignore_timeout && record->is_ip_stale() && record->record_type != HostDBType::HOST) ||
699+
if ((!ignore_timeout && record->is_ip_configured_stale() && record->record_type != HostDBType::HOST) ||
697700
(record->is_ip_timeout() && record->serve_stale_but_revalidate())) {
698701
HOSTDB_INCREMENT_DYN_STAT(hostdb_total_serve_stale_stat);
699702
if (hostDB.is_pending_dns_for_hash(hash.hash)) {
700703
Debug("hostdb", "%s",
701-
ts::bwprint(ts::bw_dbg, "stale {} {} {}, using with pending refresh", record->ip_interval(),
704+
ts::bwprint(ts::bw_dbg, "stale {} {} {}, using with pending refresh", record->ip_age(),
702705
record->ip_timestamp.time_since_epoch(), record->ip_timeout_interval)
703706
.c_str());
704707
return record;
705708
}
706709
Debug("hostdb", "%s",
707-
ts::bwprint(ts::bw_dbg, "stale {} {} {}, using while refresh", record->ip_interval(),
708-
record->ip_timestamp.time_since_epoch(), record->ip_timeout_interval)
710+
ts::bwprint(ts::bw_dbg, "stale {} {} {}, using while refresh", record->ip_age(), record->ip_timestamp.time_since_epoch(),
711+
record->ip_timeout_interval)
709712
.c_str());
710713
HostDBContinuation *c = hostDBContAllocator.alloc();
711714
HostDBContinuation::Options copt;
@@ -962,7 +965,7 @@ HostDBContinuation::lookup_done(TextView query_name, ts_seconds answer_ttl, SRVH
962965
ip_text_buffer b;
963966
Debug("hostdb", "failed for %s", hash.ip.toString(b, sizeof b));
964967
}
965-
record->ip_timestamp = hostdb_current_interval;
968+
record->ip_timestamp = hostdb_current_timestamp;
966969
record->ip_timeout_interval = ts_seconds(std::clamp(hostdb_ip_fail_timeout_interval, 1u, HOST_DB_MAX_TTL));
967970

968971
if (is_srv()) {
@@ -997,7 +1000,7 @@ HostDBContinuation::lookup_done(TextView query_name, ts_seconds answer_ttl, SRVH
9971000
HOSTDB_SUM_DYN_STAT(hostdb_ttl_stat, answer_ttl.count());
9981001

9991002
// update the TTL
1000-
record->ip_timestamp = hostdb_current_interval;
1003+
record->ip_timestamp = hostdb_current_timestamp;
10011004
record->ip_timeout_interval = std::clamp(answer_ttl, ts_seconds(1), ts_seconds(HOST_DB_MAX_TTL));
10021005

10031006
if (is_byname()) {
@@ -1206,9 +1209,9 @@ HostDBContinuation::dnsEvent(int event, HostEnt *e)
12061209
}
12071210

12081211
if (!serve_stale) { // implies r != old_r
1209-
hostDB.refcountcache->put(
1210-
r->key, r.get(), r->_record_size,
1211-
(r->ip_timestamp + r->ip_timeout_interval + ts_seconds(hostdb_serve_stale_but_revalidate)).time_since_epoch().count());
1212+
auto const duration_till_revalidate = r->expiry_time().time_since_epoch();
1213+
auto const seconds_till_revalidate = duration_cast<ts_seconds>(duration_till_revalidate).count();
1214+
hostDB.refcountcache->put(r->key, r.get(), r->_record_size, seconds_till_revalidate);
12121215
} else {
12131216
Warning("Fallback to serving stale record, skip re-update of hostdb for %.*s", int(query_name.size()), query_name.data());
12141217
}
@@ -1511,22 +1514,22 @@ HostDBContinuation::do_dns()
15111514

15121515
//
15131516
// Background event
1514-
// Just increment the current_interval. Might do other stuff
1515-
// here, like move records to the current position in the cluster.
1516-
//
1517+
// Increment the hostdb_current_timestamp which funcions as our cached version
1518+
// of ts_clock::now(). Might do other stuff here, like move records to the
1519+
// current position in the cluster.
15171520
int
15181521
HostDBContinuation::backgroundEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
15191522
{
15201523
std::string dbg;
15211524

1522-
// No nothing if hosts file checking is not enabled.
1525+
hostdb_current_timestamp = ts_clock::now();
1526+
1527+
// Do nothing if hosts file checking is not enabled.
15231528
if (hostdb_hostfile_check_interval.count() == 0) {
15241529
return EVENT_CONT;
15251530
}
15261531

1527-
hostdb_current_interval = ts_clock::now();
1528-
1529-
if ((hostdb_current_interval - hostdb_last_interval) > hostdb_hostfile_check_interval) {
1532+
if ((hostdb_current_timestamp - hostdb_last_timestamp) > hostdb_hostfile_check_interval) {
15301533
bool update_p = false; // do we need to reparse the file and update?
15311534
char path[PATH_NAME_MAX];
15321535

@@ -1539,7 +1542,7 @@ HostDBContinuation::backgroundEvent(int /* event ATS_UNUSED */, Event * /* e ATS
15391542
hostdb_hostfile_path = path;
15401543
update_p = true;
15411544
} else if (!hostdb_hostfile_path.empty()) {
1542-
hostdb_last_interval = hostdb_current_interval;
1545+
hostdb_last_timestamp = hostdb_current_timestamp;
15431546
std::error_code ec;
15441547
auto stat{ts::file::status(hostdb_hostfile_path, ec)};
15451548
if (!ec) {
@@ -1688,7 +1691,7 @@ struct ShowHostDB : public ShowCont {
16881691
CHECK_SHOW(show("<table border=1>\n"));
16891692
CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Total", r->rr_count));
16901693
CHECK_SHOW(show("<tr><td>%s</td><td>%d</td></tr>\n", "Current", r->_rr_idx.load()));
1691-
CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Stale", r->is_ip_stale() ? "Yes" : "No"));
1694+
CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Stale", r->is_ip_configured_stale() ? "Yes" : "No"));
16921695
CHECK_SHOW(show("<tr><td>%s</td><td>%s</td></tr>\n", "Timed-Out", r->is_ip_timeout() ? "Yes" : "No"));
16931696
CHECK_SHOW(show("</table>\n"));
16941697
} else {
@@ -2112,7 +2115,7 @@ ParseHostFile(ts::file::path const &path, ts_seconds hostdb_hostfile_check_inter
21122115
}
21132116
}
21142117

2115-
hostdb_hostfile_update_timestamp = hostdb_current_interval;
2118+
hostdb_hostfile_update_timestamp = hostdb_current_timestamp;
21162119
}
21172120
}
21182121

@@ -2280,10 +2283,10 @@ HostDBRecord::serve_stale_but_revalidate() const
22802283

22812284
// ip_timeout_interval == DNS TTL
22822285
// hostdb_serve_stale_but_revalidate == number of seconds
2283-
// ip_interval() is the number of seconds between now() and when the entry was inserted
2284-
if ((ip_timeout_interval + ts_seconds(hostdb_serve_stale_but_revalidate)) > ip_interval()) {
2285-
Debug_bw("hostdb", "serving stale entry {} | {} | {} as requested by config", ip_timeout_interval,
2286-
hostdb_serve_stale_but_revalidate, ip_interval());
2286+
// ip_age() is the number of seconds between now() and when the entry was inserted
2287+
if ((ip_timeout_interval + ts_seconds(hostdb_serve_stale_but_revalidate)) > ip_age()) {
2288+
Debug_bw("hostdb", "serving stale entry for {}, TTL: {}, serve_stale_for: {}, age: {} as requested by config", name(),
2289+
ip_timeout_interval, hostdb_serve_stale_but_revalidate, ip_age());
22872290
return true;
22882291
}
22892292

iocore/hostdb/I_HostDBProcessor.h

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,17 @@ struct ResolveInfo;
6161
// disk representation to decrease # of seeks.
6262
//
6363
extern int hostdb_enable;
64-
extern ts_time hostdb_current_interval;
64+
/** Epoch timestamp of the current hosts file check.
65+
*
66+
* This also functions as a cached version of ts_clock::now(). Since it is
67+
* updated in backgroundEvent which runs every second, it should be
68+
* approximately accurate to a second.
69+
*/
70+
extern ts_time hostdb_current_timestamp;
71+
72+
/** How long before any DNS response is consided stale, regardless of DNS TTL.
73+
* This corresponds to proxy.config.hostdb.verify_after.
74+
*/
6575
extern unsigned int hostdb_ip_stale_interval;
6676
extern unsigned int hostdb_ip_timeout_interval;
6777
extern unsigned int hostdb_ip_fail_timeout_interval;
@@ -325,10 +335,13 @@ class HostDBRecord : public RefCountObj
325335
/// Hash key.
326336
uint64_t key{0};
327337

328-
/// When the data was received.
338+
/// When the DNS response was received.
329339
ts_time ip_timestamp;
330340

331-
/// Valid duration of the data.
341+
/// Valid duration of the DNS response data.
342+
/// In the code this functions as the TTL in HostDB calcuations, but may not
343+
/// be the response's TTL based upon configuration such as
344+
/// proxy.config.hostdb.ttl_mode.
332345
ts_seconds ip_timeout_interval;
333346

334347
/** Atomically advance the round robin index.
@@ -414,18 +427,33 @@ class HostDBRecord : public RefCountObj
414427
/// @return The time point when the item expires.
415428
ts_time expiry_time() const;
416429

417-
ts_seconds ip_interval() const;
430+
/// @return The age of the DNS response.
431+
ts_seconds ip_age() const;
418432

433+
/// @return How long before the DNS response becomes stale (i.e., exceeds @a
434+
/// ip_timeout_interval from the time of the response).
419435
ts_seconds ip_time_remaining() const;
420436

421-
bool is_ip_stale() const;
437+
/// @return Whether the age of the DNS response exceeds @a the user's
438+
/// configured proxy.config.hostdb.verify_after value.
439+
bool is_ip_configured_stale() const;
422440

441+
/** Whether we have exceeded the DNS response's TTL (i.e., whether the DNS
442+
* response is stale). */
423443
bool is_ip_timeout() const;
424444

425445
bool is_ip_fail_timeout() const;
426446

427447
void refresh_ip();
428448

449+
/** Whether the DNS response can still be used per
450+
* proxy.config.hostdb.serve_stale_for configuration.
451+
*
452+
* @return False if serve_stale_for is not configured or if the DNS
453+
* response's age is less than TTL + the serve_stale_for value. Note that
454+
* this function will return true for DNS responses whose age is less than
455+
* TTL (i.e., for responses that are not yet stale).
456+
*/
429457
bool serve_stale_but_revalidate() const;
430458

431459
/// Deallocate @a this.
@@ -722,41 +750,44 @@ HostDBRecord::expiry_time() const
722750
}
723751

724752
inline ts_seconds
725-
HostDBRecord::ip_interval() const
753+
HostDBRecord::ip_age() const
726754
{
727755
static constexpr ts_seconds ZERO{0};
728756
static constexpr ts_seconds MAX{0x7FFFFFFF};
729-
return std::clamp(std::chrono::duration_cast<ts_seconds>((hostdb_current_interval - ip_timestamp)), ZERO, MAX);
757+
return std::clamp(std::chrono::duration_cast<ts_seconds>(hostdb_current_timestamp - ip_timestamp), ZERO, MAX);
730758
}
731759

732760
inline ts_seconds
733761
HostDBRecord::ip_time_remaining() const
734762
{
735-
return ip_timeout_interval - this->ip_interval();
763+
static constexpr ts_seconds ZERO{0};
764+
static constexpr ts_seconds MAX{0x7FFFFFFF};
765+
return std::clamp(std::chrono::duration_cast<ts_seconds>(ip_timeout_interval - this->ip_age()), ZERO, MAX);
736766
}
737767

738768
inline bool
739-
HostDBRecord::is_ip_stale() const
769+
HostDBRecord::is_ip_configured_stale() const
740770
{
741-
return ip_timeout_interval >= ts_seconds(2 * hostdb_ip_stale_interval) && ip_interval() >= ts_seconds(hostdb_ip_stale_interval);
771+
return (
772+
((ip_timeout_interval >= ts_seconds(2 * hostdb_ip_stale_interval)) && (ip_age() >= ts_seconds(hostdb_ip_stale_interval))));
742773
}
743774

744775
inline bool
745776
HostDBRecord::is_ip_timeout() const
746777
{
747-
return ip_interval() >= ip_timeout_interval;
778+
return ip_age() >= ip_timeout_interval;
748779
}
749780

750781
inline bool
751782
HostDBRecord::is_ip_fail_timeout() const
752783
{
753-
return ip_interval() >= ts_seconds(hostdb_ip_fail_timeout_interval);
784+
return ip_age() >= ts_seconds(hostdb_ip_fail_timeout_interval);
754785
}
755786

756787
inline void
757788
HostDBRecord::refresh_ip()
758789
{
759-
ip_timestamp = hostdb_current_interval;
790+
ip_timestamp = hostdb_current_timestamp;
760791
}
761792

762793
inline ts::MemSpan<HostDBInfo>

0 commit comments

Comments
 (0)