Files
waf-platform/HttpDNSSDK/sdk/ios/NewHttpDNS/HttpdnsRequestManager.m
2026-03-05 02:44:43 +08:00

646 lines
26 KiB
Objective-C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#import "HttpdnsRequestManager.h"
#import "HttpdnsHostObject.h"
#import "HttpdnsRemoteResolver.h"
#import "HttpdnsLocalResolver.h"
#import "HttpdnsInternalConstant.h"
#import "HttpdnsUtil.h"
#import "HttpdnsLog_Internal.h"
#import "HttpdnsPersistenceUtils.h"
#import "HttpdnsService_Internal.h"
#import "HttpdnsScheduleCenter.h"
#import "HttpdnsService_Internal.h"
#import "HttpdnsReachability.h"
#import "HttpdnsHostRecord.h"
#import "HttpdnsUtil.h"
#import "HttpDnsLocker.h"
#import "HttpdnsRequest_Internal.h"
#import "HttpdnsHostObjectInMemoryCache.h"
#import "HttpdnsIPQualityDetector.h"
#import "HttpdnsIpStackDetector.h"
#import "HttpdnsDB.h"
static dispatch_queue_t _persistentCacheConcurrentQueue = NULL;
static dispatch_queue_t _asyncResolveHostQueue = NULL;
typedef struct {
BOOL isResultUsable;
BOOL isResolvingRequired;
} HostObjectExamingResult;
@interface HttpdnsRequestManager()
@property (nonatomic, strong) dispatch_queue_t cacheQueue;
@property (nonatomic, assign, readwrite) NSInteger accountId;
@property (nonatomic, weak) HttpDnsService *ownerService;
@property (atomic, setter=setPersistentCacheIpEnabled:, assign) BOOL persistentCacheIpEnabled;
@property (atomic, setter=setDegradeToLocalDNSEnabled:, assign) BOOL degradeToLocalDNSEnabled;
@property (atomic, assign) BOOL atomicExpiredIPEnabled;
@property (atomic, assign) BOOL atomicPreResolveAfterNetworkChanged;
@property (atomic, assign) NSTimeInterval lastUpdateTimestamp;
@property (atomic, assign) HttpdnsNetworkStatus lastNetworkStatus;
@end
@implementation HttpdnsRequestManager {
HttpdnsHostObjectInMemoryCache *_hostObjectInMemoryCache;
HttpdnsDB *_httpdnsDB;
}
+ (void)initialize {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_persistentCacheConcurrentQueue = dispatch_queue_create("com.New.sdk.httpdns.persistentCacheOperationQueue", DISPATCH_QUEUE_CONCURRENT);
_asyncResolveHostQueue = dispatch_queue_create("com.New.sdk.httpdns.asyncResolveHostQueue", DISPATCH_QUEUE_CONCURRENT);
});
}
- (instancetype)initWithAccountId:(NSInteger)accountId ownerService:(HttpDnsService *)service {
if (self = [super init]) {
_accountId = accountId;
_ownerService = service;
HttpdnsReachability *reachability = [HttpdnsReachability sharedInstance];
self.atomicExpiredIPEnabled = NO;
self.atomicPreResolveAfterNetworkChanged = NO;
_hostObjectInMemoryCache = [[HttpdnsHostObjectInMemoryCache alloc] init];
_httpdnsDB = [[HttpdnsDB alloc] initWithAccountId:accountId];
[[HttpdnsIpStackDetector sharedInstance] redetectIpStack];
_lastNetworkStatus = reachability.currentReachabilityStatus;
_lastUpdateTimestamp = [NSDate date].timeIntervalSince1970;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleReachabilityNotification:)
name:kHttpdnsReachabilityChangedNotification
object:reachability];
[reachability startNotifier];
}
return self;
}
- (void)setExpiredIPEnabled:(BOOL)enable {
self.atomicExpiredIPEnabled = enable;
}
- (void)setCachedIPEnabled:(BOOL)enable discardRecordsHasExpiredFor:(NSTimeInterval)duration {
// 开启允许持久化缓存
[self setPersistentCacheIpEnabled:enable];
if (enable) {
dispatch_async(_persistentCacheConcurrentQueue, ^{
// 先清理过期时间超过阈值的缓存结果
[self->_httpdnsDB cleanRecordAlreadExpiredAt:[[NSDate date] timeIntervalSince1970] - duration];
// 再读取持久化缓存中的历史记录加载到内存缓存<E7BC93><E5AD98>?
[self loadCacheFromDbToMemory];
});
}
}
- (void)setPreResolveAfterNetworkChanged:(BOOL)enable {
self.atomicPreResolveAfterNetworkChanged = enable;
}
- (void)preResolveHosts:(NSArray *)hosts queryType:(HttpdnsQueryIPType)queryType {
if (![HttpdnsUtil isNotEmptyArray:hosts]) {
return;
}
__weak typeof(self) weakSelf = self;
dispatch_async(_asyncResolveHostQueue, ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
if ([strongSelf isHostsNumberLimitReached]) {
return;
}
// 分批处理每批最<E689B9><E69C80>?个域<E4B8AA><E59F9F>?
NSUInteger totalCount = hosts.count;
for (NSUInteger i = 0; i < totalCount; i += HTTPDNS_PRE_RESOLVE_BATCH_SIZE) {
NSUInteger length = MIN(HTTPDNS_PRE_RESOLVE_BATCH_SIZE, totalCount - i);
NSArray *batch = [hosts subarrayWithRange:NSMakeRange(i, length)];
NSString *combinedHostString = [batch componentsJoinedByString:@","];
HttpdnsLogDebug("Pre resolve host by async lookup, hosts: %@", combinedHostString);
HttpdnsRequest *request = [[HttpdnsRequest alloc] initWithHost:combinedHostString queryIpType:queryType];
request.accountId = strongSelf.accountId;
[request becomeNonBlockingRequest];
dispatch_async(_asyncResolveHostQueue, ^{
[strongSelf executePreResolveRequest:request retryCount:0];
});
}
});
}
#pragma mark - core method for all public query API
- (HttpdnsHostObject *)resolveHost:(HttpdnsRequest *)request {
HttpdnsLogDebug("resolveHost, request: %@", request);
NSString *host = request.host;
NSString *cacheKey = request.cacheKey;
if (request.accountId == 0 || request.accountId != self.accountId) {
request.accountId = self.accountId;
}
if ([HttpdnsUtil isEmptyString:host]) {
return nil;
}
HttpdnsHostObject *result = [_hostObjectInMemoryCache getHostObjectByCacheKey:cacheKey createIfNotExists:^id _Nonnull {
HttpdnsLogDebug("No cache for cacheKey: %@", cacheKey);
HttpdnsHostObject *newObject = [HttpdnsHostObject new];
newObject.hostName = host;
newObject.v4Ips = @[];
newObject.v6Ips = @[];
return newObject;
}];
HostObjectExamingResult examingResult = [self examineHttpdnsHostObject:result underQueryType:request.queryIpType];
BOOL isCachedResultUsable = examingResult.isResultUsable;
BOOL isResolvingRequired = examingResult.isResolvingRequired;
if (isCachedResultUsable) {
if (isResolvingRequired) {
// 缓存结果可用,但是需要请求,因为缓存结果已经过期
// 这种情况异步去解析就可以<E58FAF><E4BBA5>?
[self determineResolvingHostNonBlocking:request];
}
// 缓存是以cacheKey为准这里返回前要把host替换成用户请求的这个
result.hostName = host;
HttpdnsLogDebug("Reuse available cache for cacheKey: %@, result: %@", cacheKey, result);
// 因为缓存结果可用可以立即返<E58DB3><E8BF94>?
return result;
}
if (request.isBlockingRequest) {
// 缓存结果不可用且是同步请求需要等待结<E5BE85><E7BB93>?
return [self determineResolveHostBlocking:request];
} else {
// 缓存结果不可用且是异步请求不需要等待结<E5BE85><E7BB93>?
[self determineResolvingHostNonBlocking:request];
return nil;
}
}
- (void)determineResolvingHostNonBlocking:(HttpdnsRequest *)request {
dispatch_async(_asyncResolveHostQueue, ^{
HttpDnsLocker *locker = [HttpDnsLocker sharedInstance];
if ([locker tryLock:request.cacheKey queryType:request.queryIpType]) {
@try {
[self executeRequest:request retryCount:0];
} @catch (NSException *exception) {
HttpdnsLogDebug("determineResolvingHostNonBlocking host: %@, exception: %@", request.host, exception);
} @finally {
[locker unlock:request.cacheKey queryType:request.queryIpType];
}
} else {
HttpdnsLogDebug("determineResolvingHostNonBlocking skipped due to concurrent limitation, host: %@", request.host);
}
});
}
- (HttpdnsHostObject *)determineResolveHostBlocking:(HttpdnsRequest *)request {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block HttpdnsHostObject *result = nil;
dispatch_async(_asyncResolveHostQueue, ^{
HttpDnsLocker *locker = [HttpDnsLocker sharedInstance];
@try {
[locker lock:request.cacheKey queryType:request.queryIpType];
result = [self->_hostObjectInMemoryCache getHostObjectByCacheKey:request.cacheKey];
if (result && ![result isExpiredUnderQueryIpType:request.queryIpType]) {
// 存在且未过期,意味着其他线程已经解析到了新的结果
return;
}
result = [self executeRequest:request retryCount:0];
} @catch (NSException *exception) {
HttpdnsLogDebug("determineResolveHostBlocking host: %@, exception: %@", request.host, exception);
} @finally {
[locker unlock:request.cacheKey queryType:request.queryIpType];
dispatch_semaphore_signal(semaphore);
}
});
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(request.resolveTimeoutInSecond * NSEC_PER_SEC)));
return result;
}
- (HostObjectExamingResult)examineHttpdnsHostObject:(HttpdnsHostObject *)hostObject underQueryType:(HttpdnsQueryIPType)queryType {
if (!hostObject) {
return (HostObjectExamingResult){NO, YES};
}
if ([hostObject isIpEmptyUnderQueryIpType:queryType]) {
return (HostObjectExamingResult){NO, YES};
}
if ([hostObject isExpiredUnderQueryIpType:queryType]) {
if (self.atomicExpiredIPEnabled || [hostObject isLoadFromDB]) {
// 只有开启了允许过期缓存和开启持久化缓存情况下启动后加载到内存中的缓存才可以直接复用过期结<E69C9F><E7BB93>?
HttpdnsLogDebug("The ips is expired, but we accept it, host: %@, queryType: %ld, expiredIpEnabled: %d, isLoadFromDB: %d",
hostObject.hostName, queryType, self.atomicExpiredIPEnabled, [hostObject isLoadFromDB]);
// 复用过期结果同时也需要发起新的解析请<E69E90><E8AFB7>?
return (HostObjectExamingResult){YES, YES};
}
// 只要过期了就肯定需要请<E8A681><E8AFB7>?
return (HostObjectExamingResult){NO, YES};
}
return (HostObjectExamingResult){YES, NO};
}
- (HttpdnsHostObject *)executeRequest:(HttpdnsRequest *)request retryCount:(int)hasRetryedCount {
NSString *host = request.host;
NSString *cacheKey = request.cacheKey;
HttpdnsQueryIPType queryIPType = request.queryIpType;
HttpdnsHostObject *result = nil;
BOOL isDegradationResult = NO;
if (hasRetryedCount <= HTTPDNS_MAX_REQUEST_RETRY_TIME) {
HttpdnsLogDebug("Internal request starts, host: %@, request: %@", host, request);
NSError *error = nil;
NSArray<HttpdnsHostObject *> *resultArray = [[HttpdnsRemoteResolver new] resolve:request error:&error];
if (error) {
HttpdnsLogDebug("Internal request error, host: %@, error: %@", host, error);
HttpdnsScheduleCenter *scheduleCenter = self.ownerService.scheduleCenter;
[scheduleCenter rotateServiceServerHost];
// 确保一定的重试间隔
hasRetryedCount++;
[NSThread sleepForTimeInterval:hasRetryedCount * 0.25];
return [self executeRequest:request retryCount:hasRetryedCount];
}
if ([HttpdnsUtil isEmptyArray:resultArray]) {
HttpdnsLogDebug("Internal request get empty result array, host: %@", host);
return nil;
}
// 这个路径里host只会有一个所以直接取第一个处理就<E79086><E5B0B1>?
result = resultArray.firstObject;
} else {
if (!self.degradeToLocalDNSEnabled) {
HttpdnsLogDebug("Internal remote request retry count exceed limit, host: %@", host);
return nil;
}
result = [[HttpdnsLocalResolver new] resolve:request];
if (!result) {
HttpdnsLogDebug("Fallback to local dns resolver, but still get no result, host: %@", host);
return nil;
}
isDegradationResult = YES;
}
HttpdnsLogDebug("Internal request finished, host: %@, cacheKey: %@, isDegradationResult: %d, result: %@ ",
host, cacheKey, isDegradationResult, result);
// merge之后返回的应当是存储在缓存中的实际对象而非请求过程中构造出来的对象
HttpdnsHostObject *lookupResult = [self mergeLookupResultToManager:result host:host cacheKey:cacheKey underQueryIpType:queryIPType];
// 返回一个快照避免进行中的一些缓存调整影响返回去的结<E79A84><E7BB93>?
return [lookupResult copy];
}
- (void)executePreResolveRequest:(HttpdnsRequest *)request retryCount:(int)hasRetryedCount {
NSString *host = request.host;
HttpdnsQueryIPType queryIPType = request.queryIpType;
BOOL isDegradationResult = NO;
if (hasRetryedCount > HTTPDNS_MAX_REQUEST_RETRY_TIME) {
HttpdnsLogDebug("PreResolve remote request retry count exceed limit, host: %@", host);
return;
}
HttpdnsLogDebug("PreResolve request starts, host: %@, request: %@", host, request);
NSError *error = nil;
NSArray<HttpdnsHostObject *> *resultArray = [[HttpdnsRemoteResolver new] resolve:request error:&error];
if (error) {
HttpdnsLogDebug("PreResolve request error, host: %@, error: %@", host, error);
HttpdnsScheduleCenter *scheduleCenter = self.ownerService.scheduleCenter;
[scheduleCenter rotateServiceServerHost];
// 确保一定的重试间隔
hasRetryedCount++;
[NSThread sleepForTimeInterval:hasRetryedCount * 0.25];
// 预解析重试需保持“多域名预解析”的语义,不能误用单域名执行路径
[self executePreResolveRequest:request retryCount:hasRetryedCount];
return;
}
if ([HttpdnsUtil isEmptyArray:resultArray]) {
HttpdnsLogDebug("PreResolve request get empty result array, host: %@", host);
return;
}
HttpdnsLogDebug("PreResolve request finished, host: %@, isDegradationResult: %d, result: %@ ",
host, isDegradationResult, resultArray);
for (HttpdnsHostObject *result in resultArray) {
// merge之后返回的应当是存储在缓存中的实际对象而非请求过程中构造出来的对象
// 预解析不支持SDNS所以cacheKey只能是单独的每一个hostName
[self mergeLookupResultToManager:result host:result.hostName cacheKey:result.hostName underQueryIpType:queryIPType];
}
}
- (HttpdnsHostObject *)mergeLookupResultToManager:(HttpdnsHostObject *)result host:host cacheKey:(NSString *)cacheKey underQueryIpType:(HttpdnsQueryIPType)queryIpType {
if (!result) {
return nil;
}
NSArray<HttpdnsIpObject *> *v4IpObjects = [result getV4Ips];
NSArray<HttpdnsIpObject *> *v6IpObjects = [result getV6Ips];
NSString* extra = [result getExtra];
BOOL hasNoIpv4Record = NO;
BOOL hasNoIpv6Record = NO;
if (queryIpType & HttpdnsQueryIPTypeIpv4 && [HttpdnsUtil isEmptyArray:v4IpObjects]) {
hasNoIpv4Record = YES;
}
if (queryIpType & HttpdnsQueryIPTypeIpv6 && [HttpdnsUtil isEmptyArray:v6IpObjects]) {
hasNoIpv6Record = YES;
}
HttpdnsHostObject *cachedHostObject = [_hostObjectInMemoryCache getHostObjectByCacheKey:cacheKey];
if (!cachedHostObject) {
HttpdnsLogDebug("Create new hostObject for cache, cacheKey: %@, host: %@", cacheKey, host);
cachedHostObject = [[HttpdnsHostObject alloc] init];
}
[cachedHostObject setCacheKey:cacheKey];
[cachedHostObject setClientIp:result.clientIp];
[cachedHostObject setHostName:host];
[cachedHostObject setIsLoadFromDB:NO];
[cachedHostObject setHasNoIpv4Record:hasNoIpv4Record];
[cachedHostObject setHasNoIpv6Record:hasNoIpv6Record];
if ([HttpdnsUtil isNotEmptyArray:v4IpObjects]) {
[cachedHostObject setV4Ips:v4IpObjects];
[cachedHostObject setV4TTL:result.getV4TTL];
[cachedHostObject setLastIPv4LookupTime:result.lastIPv4LookupTime];
}
if ([HttpdnsUtil isNotEmptyArray:v6IpObjects]) {
[cachedHostObject setV6Ips:v6IpObjects];
[cachedHostObject setV6TTL:result.getV6TTL];
[cachedHostObject setLastIPv6LookupTime:result.lastIPv6LookupTime];
}
if ([HttpdnsUtil isNotEmptyString:extra]) {
[cachedHostObject setExtra:extra];
}
HttpdnsLogDebug("Updated hostObject to cached, cacheKey: %@, host: %@", cacheKey, host);
// 由于从缓存中读取到的是拷贝出来的新对象,字段赋值不会影响缓存中的值对象,因此这里无论如何都要放回缓存
[_hostObjectInMemoryCache setHostObject:cachedHostObject forCacheKey:cacheKey];
[self persistToDB:cacheKey hostObject:cachedHostObject];
NSArray *ipv4StrArray = [cachedHostObject getV4IpStrings];
if ([HttpdnsUtil isNotEmptyArray:ipv4StrArray]) {
[self initiateQualityDetectionForIP:ipv4StrArray forHost:host cacheKey:cacheKey];
}
NSArray *ipv6StrArray = [cachedHostObject getV6IpStrings];
if ([HttpdnsUtil isNotEmptyArray:ipv6StrArray]) {
[self initiateQualityDetectionForIP:ipv6StrArray forHost:host cacheKey:cacheKey];
}
return cachedHostObject;
}
- (void)initiateQualityDetectionForIP:(NSArray *)ipArray forHost:(NSString *)host cacheKey:(NSString *)cacheKey {
HttpDnsService *service = self.ownerService ?: [HttpDnsService sharedInstance];
NSDictionary<NSString *, NSNumber *> *dataSource = [service getIPRankingDatasource];
if (!dataSource || ![dataSource objectForKey:host]) {
return;
}
NSNumber *port = [dataSource objectForKey:host];
for (NSString *ip in ipArray) {
[[HttpdnsIPQualityDetector sharedInstance] scheduleIPQualityDetection:cacheKey
ip:ip
port:port
callback:^(NSString * _Nonnull cacheKey, NSString * _Nonnull ip, NSInteger costTime) {
[self->_hostObjectInMemoryCache updateQualityForCacheKey:cacheKey forIp:ip withConnectedRT:costTime];
}];
}
}
- (BOOL)isHostsNumberLimitReached {
if ([_hostObjectInMemoryCache count] >= HTTPDNS_MAX_MANAGE_HOST_NUM) {
HttpdnsLogDebug("Can't handle more than %d hosts due to the software configuration.", HTTPDNS_MAX_MANAGE_HOST_NUM);
return YES;
}
return NO;
}
- (void)handleReachabilityNotification:(NSNotification *)notification {
[self networkChanged];
}
- (void)networkChanged {
HttpdnsNetworkStatus currentStatus = [[HttpdnsReachability sharedInstance] currentReachabilityStatus];
NSString *currentStatusString = [[HttpdnsReachability sharedInstance] currentReachabilityString];
// 重新检测协议栈代价小所以只要网络切换就发起检<E8B5B7><E6A380>?
// 但考虑到网络切换后不稳定还是延迟1秒才发起
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
[[HttpdnsIpStackDetector sharedInstance] redetectIpStack];
});
NSTimeInterval currentTimestamp = [NSDate date].timeIntervalSince1970;
BOOL statusChanged = (_lastNetworkStatus != currentStatus);
// 仅在以下情况下响应网络变化去尝试更新缓存:
// - 距离上次处理事件至少过去了较长时间<E997B4><EFBC8C>?
// - 网络状态发生变化且至少过去了较短时<E79FAD><E697B6>?
NSTimeInterval elapsedTime = currentTimestamp - _lastUpdateTimestamp;
if (elapsedTime >= 5 || (statusChanged && elapsedTime >= 1)) {
HttpdnsLogDebug("Processing network change: oldStatus: %ld, newStatus: %ld(%@), elapsedTime=%.2f seconds",
_lastNetworkStatus, currentStatus, currentStatusString, elapsedTime);
// 更新调度
// 网络在切换过程中可能不稳定所以发送请求前等待2<E5BE85><32>?
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
HttpdnsScheduleCenter *scheduleCenter = self.ownerService.scheduleCenter;
[scheduleCenter asyncUpdateRegionScheduleConfig];
});
// 复杂逻辑(仅注释关键点,避免冗余):
// 网络切换后只预解析“cacheKey 等于 hostName”的条目<E69DA1><E79BAE>?
// 这些条目代表标准域名缓存SDNS 等使用自定义 cacheKey 的记录不在此批次处理<E5A484><E79086>?
NSArray *allKeys = [_hostObjectInMemoryCache allCacheKeys];
NSMutableArray<NSString *> *hostArray = [NSMutableArray array];
for (NSString *key in allKeys) {
HttpdnsHostObject *obj = [self->_hostObjectInMemoryCache getHostObjectByCacheKey:key];
if (!obj) {
continue;
}
NSString *cacheKey = [obj getCacheKey];
NSString *hostName = [obj getHostName];
if (cacheKey && hostName && [cacheKey isEqualToString:hostName]) {
[hostArray addObject:hostName];
}
}
// 预解<E9A284><E8A7A3>?
// 网络在切换过程中可能不稳定所以在清理缓存和发送请求前等待3<E5BE85><33>?
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
// 仅清理“hostName 键”的缓存<EFBC8C><E4BF9D>?SDNS 等自定义 cacheKey 的记<E79A84><E8AEB0>?
for (NSString *host in hostArray) {
[self->_hostObjectInMemoryCache removeHostObjectByCacheKey:host];
}
if (self.atomicPreResolveAfterNetworkChanged && hostArray.count > 0) {
HttpdnsLogDebug("Network changed, pre resolve for host-key entries: %@", hostArray);
[self preResolveHosts:hostArray queryType:HttpdnsQueryIPTypeAuto];
}
});
// 更新时间戳和状<E5928C><E78AB6>?
_lastNetworkStatus = currentStatus;
_lastUpdateTimestamp = currentTimestamp;
} else {
HttpdnsLogDebug("Ignoring network change event: oldStatus: %ld, newStatus: %ld(%@), elapsedTime=%.2f seconds",
_lastNetworkStatus, currentStatus, currentStatusString, elapsedTime);
}
}
#pragma mark -
#pragma mark - disable status Setter and Getter Method
- (dispatch_queue_t)cacheQueue {
if (!_cacheQueue) {
_cacheQueue = dispatch_queue_create("com.New.sdk.httpdns.cacheDisableStatusQueue", DISPATCH_QUEUE_SERIAL);
}
return _cacheQueue;
}
#pragma mark -
#pragma mark - Flag for Disable and Sniffer Method
- (void)loadCacheFromDbToMemory {
NSArray<HttpdnsHostRecord *> *hostRecords = [self->_httpdnsDB getAllRecords];
if ([HttpdnsUtil isEmptyArray:hostRecords]) {
return;
}
for (HttpdnsHostRecord *hostRecord in hostRecords) {
NSString *hostName = hostRecord.hostName;
NSString *cacheKey = hostRecord.cacheKey;
HttpdnsHostObject *hostObject = [HttpdnsHostObject fromDBRecord:hostRecord];
// 从持久层加载到内存的缓存需要做个标记App启动后从缓存使用结果时根据标记做特殊处<E6AE8A><E5A484>?
[hostObject setIsLoadFromDB:YES];
[self->_hostObjectInMemoryCache setHostObject:hostObject forCacheKey:cacheKey];
NSArray *v4IpStrArr = [hostObject getV4IpStrings];
if ([HttpdnsUtil isNotEmptyArray:v4IpStrArr]) {
[self initiateQualityDetectionForIP:v4IpStrArr forHost:hostName cacheKey:cacheKey];
}
NSArray *v6IpStrArr = [hostObject getV6IpStrings];
if ([HttpdnsUtil isNotEmptyArray:v6IpStrArr]) {
[self initiateQualityDetectionForIP:v6IpStrArr forHost:hostName cacheKey:cacheKey];
}
}
}
- (void)cleanMemoryAndPersistentCacheOfHostArray:(NSArray<NSString *> *)hostArray {
for (NSString *host in hostArray) {
if ([HttpdnsUtil isNotEmptyString:host]) {
[_hostObjectInMemoryCache removeHostObjectByCacheKey:host];
}
}
// 清空数据库数<E5BA93><E695B0>?
dispatch_async(_persistentCacheConcurrentQueue, ^{
[self->_httpdnsDB deleteByHostNameArr:hostArray];
});
}
- (void)cleanMemoryAndPersistentCacheOfAllHosts {
[_hostObjectInMemoryCache removeAllHostObjects];
// 清空数据库数<E5BA93><E695B0>?
dispatch_async(_persistentCacheConcurrentQueue, ^{
[self->_httpdnsDB deleteAll];
});
}
- (void)persistToDB:(NSString *)cacheKey hostObject:(HttpdnsHostObject *)hostObject {
if (!_persistentCacheIpEnabled) {
return;
}
dispatch_async(_persistentCacheConcurrentQueue, ^{
HttpdnsHostRecord *hostRecord = [hostObject toDBRecord];
[self->_httpdnsDB createOrUpdate:hostRecord];
});
}
#pragma mark -
#pragma mark - 以下函数仅用于测试目<E8AF95><E79BAE>?
- (NSString *)showMemoryCache {
NSString *cacheDes;
cacheDes = [NSString stringWithFormat:@"%@", _hostObjectInMemoryCache];
return cacheDes;
}
- (void)cleanAllHostMemoryCache {
[_hostObjectInMemoryCache removeAllHostObjects];
}
- (void)syncLoadCacheFromDbToMemory {
[self loadCacheFromDbToMemory];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end