| 1883 | } |
| 1884 | |
| 1885 | Optional<std::tuple<Version, Version, std::vector<TLogLockResult>>> TagPartitionedLogSystem::getDurableVersion( |
| 1886 | UID dbgid, |
| 1887 | LogLockInfo lockInfo, |
| 1888 | std::vector<Reference<AsyncVar<bool>>> failed, |
| 1889 | Optional<Version> lastEnd) { |
| 1890 | |
| 1891 | Reference<LogSet> logSet = lockInfo.logSet; |
| 1892 | // To ensure consistent recovery, the number of servers NOT in the write quorum plus the number of servers NOT |
| 1893 | // in the read quorum have to be strictly less than the replication factor. Otherwise there could be a replica |
| 1894 | // set consistent entirely of servers that are out of date due to not being in the write quorum or unavailable |
| 1895 | // due to not being in the read quorum. So with N = # of tlogs, W = antiquorum, R = required count, F = |
| 1896 | // replication factor, W + (N - R) < F, and optimally (N-W)+(N-R)=F-1. Thus R=N+1-F+W. |
| 1897 | int requiredCount = |
| 1898 | (int)logSet->logServers.size() + 1 - logSet->tLogReplicationFactor + logSet->tLogWriteAntiQuorum; |
| 1899 | ASSERT(requiredCount > 0 && requiredCount <= logSet->logServers.size()); |
| 1900 | ASSERT(logSet->tLogReplicationFactor >= 1 && logSet->tLogReplicationFactor <= logSet->logServers.size()); |
| 1901 | ASSERT(logSet->tLogWriteAntiQuorum >= 0 && logSet->tLogWriteAntiQuorum < logSet->logServers.size()); |
| 1902 | |
| 1903 | std::vector<LocalityData> availableItems, badCombo; |
| 1904 | std::vector<TLogLockResult> results; |
| 1905 | std::string sServerState; |
| 1906 | LocalityGroup unResponsiveSet; |
| 1907 | for (int t = 0; t < logSet->logServers.size(); t++) { |
| 1908 | if (lockInfo.replies[t].isReady() && !lockInfo.replies[t].isError() && (!failed.size() || !failed[t]->get())) { |
| 1909 | results.push_back(lockInfo.replies[t].get()); |
| 1910 | availableItems.push_back(logSet->tLogLocalities[t]); |
| 1911 | sServerState += 'a'; |
| 1912 | } else { |
| 1913 | unResponsiveSet.add(logSet->tLogLocalities[t]); |
| 1914 | sServerState += 'f'; |
| 1915 | } |
| 1916 | } |
| 1917 | |
| 1918 | // Check if the list of results is not larger than the anti quorum |
| 1919 | bool bTooManyFailures = (results.size() <= logSet->tLogWriteAntiQuorum); |
| 1920 | |
| 1921 | // Check if failed logs complete the policy |
| 1922 | bTooManyFailures = bTooManyFailures || ((unResponsiveSet.size() >= logSet->tLogReplicationFactor) && |
| 1923 | (unResponsiveSet.validate(logSet->tLogPolicy))); |
| 1924 | |
| 1925 | // Check all combinations of the AntiQuorum within the failed |
| 1926 | if (!bTooManyFailures && (logSet->tLogWriteAntiQuorum) && |
| 1927 | (!validateAllCombinations( |
| 1928 | badCombo, unResponsiveSet, logSet->tLogPolicy, availableItems, logSet->tLogWriteAntiQuorum, false))) { |
| 1929 | TraceEvent("EpochEndBadCombo", dbgid) |
| 1930 | .detail("Required", requiredCount) |
| 1931 | .detail("Present", results.size()) |
| 1932 | .detail("ServerState", sServerState); |
| 1933 | bTooManyFailures = true; |
| 1934 | } |
| 1935 | |
| 1936 | ASSERT(logSet->logServers.size() == lockInfo.replies.size()); |
| 1937 | if (!bTooManyFailures) { |
| 1938 | std::sort(results.begin(), results.end(), [](const TLogLockResult& a, const TLogLockResult& b) -> bool { |
| 1939 | return a.end < b.end; |
| 1940 | }); |
| 1941 | int absent = logSet->logServers.size() - results.size(); |
| 1942 | int safe_range_begin = logSet->tLogWriteAntiQuorum; |
nothing calls this directly
no test coverage detected