Roll abseil_revision b2dc72c17a..de71511109

Change Log:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+log/b2dc72c17a..de71511109
Full diff:
https://chromium.googlesource.com/external/github.com/abseil/abseil-cpp/+/b2dc72c17a..de71511109

Bug: None
Change-Id: Ic3cf2a0b7e9559867f8694142beddae65596dc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3173136
Reviewed-by: Danil Chapovalov <danilchap@chromium.org>
Commit-Queue: Mirko Bonadei <mbonadei@chromium.org>
Cr-Commit-Position: refs/heads/main@{#923780}
NOKEYCHECK=True
GitOrigin-RevId: 2fc881511cfa81cc144ea5d3bb169d568c01173c
diff --git a/README.chromium b/README.chromium
index 0c6a6a8..4c4ca86 100644
--- a/README.chromium
+++ b/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: b2dc72c17ac663885b62334d334da9f8970543b5
+Revision: de71511109d967000e68baedb75de104adb2b778
 Security Critical: yes
 
 Description:
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index ca03d9b..4b13370 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -68,6 +68,7 @@
   hashes_bitwise_or.store(0, std::memory_order_relaxed);
   hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
   hashes_bitwise_xor.store(0, std::memory_order_relaxed);
+  max_reserve.store(0, std::memory_order_relaxed);
 
   create_time = absl::Now();
   // The inliner makes hardcoded skip_count difficult (especially when combined
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
index d86207f..812118e 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -80,6 +80,7 @@
   std::atomic<size_t> hashes_bitwise_or;
   std::atomic<size_t> hashes_bitwise_and;
   std::atomic<size_t> hashes_bitwise_xor;
+  std::atomic<size_t> max_reserve;
 
   // All of the fields below are set by `PrepareForSampling`, they must not be
   // mutated in `Record*` functions.  They are logically `const` in that sense.
@@ -107,6 +108,18 @@
       std::memory_order_relaxed);
 }
 
+inline void RecordReservationSlow(HashtablezInfo* info,
+                                  size_t target_capacity) {
+  info->max_reserve.store(
+      (std::max)(info->max_reserve.load(std::memory_order_relaxed),
+                 target_capacity),
+      std::memory_order_relaxed);
+}
+
+inline void RecordClearedReservationSlow(HashtablezInfo* info) {
+  info->max_reserve.store(0, std::memory_order_relaxed);
+}
+
 inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
                                      size_t capacity) {
   info->size.store(size, std::memory_order_relaxed);
@@ -170,6 +183,16 @@
     RecordRehashSlow(info_, total_probe_length);
   }
 
+  inline void RecordReservation(size_t target_capacity) {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordReservationSlow(info_, target_capacity);
+  }
+
+  inline void RecordClearedReservation() {
+    if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+    RecordClearedReservationSlow(info_);
+  }
+
   inline void RecordInsert(size_t hash, size_t distance_from_desired) {
     if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
     RecordInsertSlow(info_, hash, distance_from_desired);
@@ -199,6 +222,8 @@
 
   inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
   inline void RecordRehash(size_t /*total_probe_length*/) {}
+  inline void RecordReservation(size_t /*target_capacity*/) {}
+  inline void RecordClearedReservation() {}
   inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
   inline void RecordErase() {}
 
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index 53fcfe6..f053c19 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -91,6 +91,7 @@
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
   EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
+  EXPECT_EQ(info.max_reserve.load(), 0);
   EXPECT_GE(info.create_time, test_start);
 
   info.capacity.store(1, std::memory_order_relaxed);
@@ -101,6 +102,7 @@
   info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
+  info.max_reserve.store(1, std::memory_order_relaxed);
   info.create_time = test_start - absl::Hours(20);
 
   info.PrepareForSampling();
@@ -113,6 +115,7 @@
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
   EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
+  EXPECT_EQ(info.max_reserve.load(), 0);
   EXPECT_GE(info.create_time, test_start);
 }
 
@@ -187,6 +190,22 @@
   EXPECT_EQ(info.num_rehashes.load(), 1);
 }
 
+TEST(HashtablezInfoTest, RecordReservation) {
+  HashtablezInfo info;
+  absl::MutexLock l(&info.init_mu);
+  info.PrepareForSampling();
+  RecordReservationSlow(&info, 3);
+  EXPECT_EQ(info.max_reserve.load(), 3);
+
+  RecordReservationSlow(&info, 2);
+  // High watermark does not change
+  EXPECT_EQ(info.max_reserve.load(), 3);
+
+  RecordReservationSlow(&info, 10);
+  // High watermark does change
+  EXPECT_EQ(info.max_reserve.load(), 10);
+}
+
 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
 TEST(HashtablezSamplerTest, SmallSampleParameter) {
   SetHashtablezEnabled(true);
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index f4919ce..212052e 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -1069,6 +1069,8 @@
     // past that we simply deallocate the array.
     if (capacity_ > 127) {
       destroy_slots();
+
+      infoz().RecordClearedReservation();
     } else if (capacity_) {
       for (size_t i = 0; i != capacity_; ++i) {
         if (IsFull(ctrl_[i])) {
@@ -1382,14 +1384,20 @@
     if (n == 0 && size_ == 0) {
       destroy_slots();
       infoz().RecordStorageChanged(0, 0);
+      infoz().RecordClearedReservation();
       return;
     }
+
     // bitor is a faster way of doing `max` here. We will round up to the next
     // power-of-2-minus-1, so bitor is good enough.
     auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size()));
     // n == 0 unconditionally rehashes as per the standard.
     if (n == 0 || m > capacity_) {
       resize(m);
+
+      // This is after resize, to ensure that we have completed the allocation
+      // and have potentially sampled the hashtable.
+      infoz().RecordReservation(n);
     }
   }
 
@@ -1397,6 +1405,10 @@
     if (n > size() + growth_left()) {
       size_t m = GrowthToLowerboundCapacity(n);
       resize(NormalizeCapacity(m));
+
+      // This is after resize, to ensure that we have completed the allocation
+      // and have potentially sampled the hashtable.
+      infoz().RecordReservation(n);
     }
   }
 
@@ -1638,6 +1650,7 @@
         PolicyTraits::destroy(&alloc_ref(), slots_ + i);
       }
     }
+
     // Unpoison before returning the memory to the allocator.
     SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
     Deallocate<alignof(slot_type)>(
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 4012a3a..b46c492 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -2049,15 +2049,31 @@
   std::vector<IntTable> tables;
   for (int i = 0; i < 1000000; ++i) {
     tables.emplace_back();
+
+    const bool do_reserve = (i % 10 > 5);
+    const bool do_rehash = !do_reserve && (i % 10 > 0);
+
+    if (do_reserve) {
+      // Don't reserve on all tables.
+      tables.back().reserve(10 * (i % 10));
+    }
+
     tables.back().insert(1);
     tables.back().insert(i % 5);
+
+    if (do_rehash) {
+      // Rehash some other tables.
+      tables.back().rehash(10 * (i % 10));
+    }
   }
   size_t end_size = 0;
   std::unordered_map<size_t, int> observed_checksums;
+  std::unordered_map<ssize_t, int> reservations;
   end_size += sampler.Iterate([&](const HashtablezInfo& info) {
     if (preexisting_info.count(&info) == 0) {
       observed_checksums[info.hashes_bitwise_xor.load(
           std::memory_order_relaxed)]++;
+      reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
     }
     ++end_size;
   });
@@ -2068,6 +2084,15 @@
   for (const auto& [_, count] : observed_checksums) {
     EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
   }
+
+  EXPECT_EQ(reservations.size(), 10);
+  for (const auto& [reservation, count] : reservations) {
+    EXPECT_GE(reservation, 0);
+    EXPECT_LT(reservation, 100);
+
+    EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.1, 0.05)
+        << reservation;
+  }
 }
 #endif  // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
 
diff --git a/absl/profiling/internal/sample_recorder.h b/absl/profiling/internal/sample_recorder.h
index a257ea5..5e04a9c 100644
--- a/absl/profiling/internal/sample_recorder.h
+++ b/absl/profiling/internal/sample_recorder.h
@@ -41,7 +41,6 @@
 // samples maintained by the SampleRecorder.  Type T defines the sampled data.
 template <typename T>
 struct Sample {
- public:
   // Guards the ability to restore the sample to a pristine state.  This
   // prevents races with sampling and resurrecting an object.
   absl::Mutex init_mu;
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index 115705a..29af978 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -708,8 +708,8 @@
   if (btree_enabled()) {
     // TODO(b/192061034): keep legacy 10% growth rate: consider other rates.
     rep = ForceBtree(rep);
-    const size_t alloc_hint = (std::min)(kMaxFlatLength, rep->length / 10);
-    rep = CordRepBtree::Append(rep->btree(), src, alloc_hint);
+    const size_t min_growth = std::max<size_t>(rep->length / 10, src.size());
+    rep = CordRepBtree::Append(rep->btree(), src, min_growth - src.size());
   } else {
     // Use new block(s) for any remaining bytes that were not handled above.
     // Alloc extra memory only if the right child of the root of the new tree
diff --git a/absl/strings/internal/cord_rep_btree.cc b/absl/strings/internal/cord_rep_btree.cc
index 8fe589f..6d53ab6 100644
--- a/absl/strings/internal/cord_rep_btree.cc
+++ b/absl/strings/internal/cord_rep_btree.cc
@@ -96,7 +96,8 @@
     maybe_dump_data(rep);
     DumpAll(substring->child, include_contents, stream, depth + 1);
   } else if (rep->tag >= FLAT) {
-    stream << "Flat, len = " << rep->length;
+    stream << "Flat, len = " << rep->length
+           << ", cap = " << rep->flat()->Capacity();
     maybe_dump_data(rep);
   } else if (rep->tag == EXTERNAL) {
     stream << "Extn, len = " << rep->length;
diff --git a/absl/time/time.h b/absl/time/time.h
index e9cbce8..5abd815 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -480,8 +480,9 @@
 // ToInt64Hours()
 //
 // Helper functions that convert a Duration to an integral count of the
-// indicated unit. These functions are shorthand for the `IDivDuration()`
-// function above; see its documentation for details about overflow, etc.
+// indicated unit. These return the same results as the `IDivDuration()`
+// function, though they usually do so more efficiently; see the
+// documentation of `IDivDuration()` for details about overflow, etc.
 //
 // Example:
 //