code: public int truncate(long newTruncationPoint) {
          int truncated = 0;
          if (m_map.isEmpty()) {
              m_map.add(range(newTruncationPoint, newTruncationPoint));
              m_hasSentinel = true;
              return truncated;
          }
          if (newTruncationPoint < getFirstSeqNo()) {
              return truncated;
          }
          // Sentinel doesn't count as valid sequence
          if (m_hasSentinel) {
              truncated -= 1;
          }
          final Iterator<Range<Long>> iter = m_map.asRanges().iterator();
          while (iter.hasNext()) {
              final Range<Long> next = iter.next();
              if (end(next) < newTruncationPoint) {
                  truncated += end(next) - start(next) + 1;
                  iter.remove();
              } else if (next.contains(newTruncationPoint)) {
                  truncated += newTruncationPoint - start(next) + 1;
                  iter.remove();
                  m_map.add(range(newTruncationPoint, end(next)));
                  m_hasSentinel = true;
                  return truncated;
              } else {
                  break;
              }
          }
          if (!m_map.contains(newTruncationPoint)) {
              m_map.add(range(newTruncationPoint, newTruncationPoint));
              m_hasSentinel = true;
          }
          return truncated;
      }
docs: Truncate the tracker to the given safe point. After truncation, the new
  safe point will be the first sequence number of the tracker. If the new safe point
  is before the first sequence number of the tracker, it's a no-op. If the
  map is empty, truncation point will be the new safe point of tracker.
  @param newTruncationPoint    New safe point
  @return number of sequence be truncated