1 Temmuz 2019 Pazartesi

ImmutableRangeSet Sınıfı

constructor
Şöyle yaparız.
ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
        .add(Range.closed(1, 10).canonical(DiscreteDomain.integers()))
        .add(Range.closed(11, 15))
        .build()
asSet metodu
Sınıf içindeki tüm rakamları set olarak döndürür

copyOf metodu
Çakışan aralıklar varsa exception fırlatır. Çıktı olarak şunu alırız
java.lang.IllegalArgumentException: 
Overlapping ranges not permitted but found [0..2] overlapping [1..4]
Örnek
Şöyle yaparız.
 //given
ImmutableList<Range<Integer>> ranges = ImmutableList.of(
  Range.closed(0, 2),
  Range.closed(3, 4),
  Range.closed(9, 10)
);
//when
ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.copyOf(ranges);
//then
assertThat(rangeSet.asSet(DiscreteDomain.integers()))
  .containsOnly(0, 1, 2, 3, 4, 9, 10);
unionOf metodu
Çakışan aralıklar olsa bilr bunları birleştirir.
Örnek
Elimizde şöyle bir kod olsun.
//given
ImmutableList<Range<Integer>> ranges = ImmutableList.of(
  Range.closed(0, 2),
  Range.closed(1, 4),
  Range.closed(9, 10)
);
Şöyle yaparız.
//when
ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.unionOf(ranges);

19 Haziran 2019 Çarşamba

Caffeine AsyncCache Arayüzü

Örnek
Şöyle yaparız.
AsyncCache<String, Cat> asyncCache = Caffeine.newBuilder()
        .expireAfterWrite(1, TimeUnit.HOURS)
        .recordStats()
        .maximumSize(100)
        .buildAsync();

Cache<String, Cat> cache = Caffeine.newBuilder()
        .expireAfterWrite(1, TimeUnit.HOURS)
        .maximumSize(100)
        .recordStats()
        .build();

18 Haziran 2019 Salı

RateLimiter Sınıfı

Giriş
Şu satırı dahil ederiz.
import com.google.common.util.concurrent.RateLimiter;
Bu sınıfla ile kaynaklara erişime sınırlama konuluyor. Bu sınıfa aynı zamanda "Message Throttling" da deniliyor.

Kaynaklara Sınır Koymak
Rate Limiting Algorithms yazısına taşıdım

Guava Ne Kullanıyor?
Guava Spike Control Policy yöntemini kullanıyor. Kalıtım şöyle
RateLimiter <- SmoothRateLimiter <- SmoothWarmingUp 
                                                        <- SmoothBursty
Açıklaması şöyle
The configured rate is distributed evenly across the interval. (more like a sliding window)
Sınıfın Hatası Var
Açıklaması şöyle.
It seems like Guava RateLimiter can only work up to a limit of 1,000,000 aquire calls per second. If you try to do 1,000,001 aquire calls per second the call to aquire will not wait at all (return value of aquire() is always 0.0) -> no throttling occurs.
Under Utilization
Açıklaması şöyle
A SmoothRateLimiter has four member variables:

storedPermits - used to model past underutilization as described in Design section.
maxPermits - maximum number of storedPermits.
stableIntervalMicros - the interval between two requests at the stable rate. Its value should be 1 / rate.
nextFreeTicketMicros - the time when next permit can be granted. It is updated after each permit is granted.
Eğer SmoothRateLimiter sınıfındaki kod şöyle. Eğer under utilization varsa storedPersmit alanı en fazla maxPersmits olacak kadar tekrar dolduruluyor. storedPermits alanı doluysa, RateLimiter bu alan tekrar 0 oluncaya kadar acqiure() metodlarına hemen cevap veriyor. Yani beklemiyor. Bu da en bazı durumlarda RateLimiter sınıfının kendisini tekrar toparlayıncaya kadar bazı istekleri geçirdiği anlamına gelir.
void resync(long nowMicros) {
  // if nextFreeTicket is in the past, resync to now
  if (nowMicros > nextFreeTicketMicros) {
    double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();
    storedPermits = min(maxPermits, storedPermits + newPermits);
    nextFreeTicketMicros = nowMicros;
  }
}
C++
Benzer bir şeyi C++ ile şöyle yaparız
#include <chrono>

class RateController {
  using clk_t        = std::chrono::system_clock;

public:
  RateController(unsigned limit, long time_slice_seconds)
      : n_(limit), time_slice_(time_slice_seconds) {}

  bool check() {
    auto duration_since_epoch = clk_t::now().time_since_epoch();
    long curr_time_slice =
        std::chrono::duration_cast<std::chrono::seconds>(duration_since_epoch).count() /
        time_slice_; // integer division!

    if (curr_time_slice != last_time_slice_) {
      last_time_slice_ = curr_time_slice;
      count_           = 0;
    }
    ++count_;
    return (count_ <= n_);
  }

private:
  unsigned n_;
  long     time_slice_;
  long     last_time_slice_ = 0;
  unsigned count_           = 0;
  ;
};

acquire metodu
Şöyle yaparız.
while (true) {
  rateLimiter.acquire();
  ...
}
create metodu - SmoothBursty
İmzası şöyle
static RateLimiter create(double permitsPerSecond)
Metod altta şöyledir.
static RateLimiter create(SleepingStopwatch stopwatch, double permitsPerSecond) {

  RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0 /* maxBurstSeconds */); 
  rateLimiter.setRate(permitsPerSecond);
  return rateLimiter;
}
Örnek
Saniyede bir oran için şöyle yaparız.
RateLimiter msgLimiter  = RateLimiter.create(1);
Örnek
Elimizde şöyle bir kod olsun. RateLimiter dolu başlar. Bekleme aralıkları sabit olduğu için hep aynı süre bekleriz
RateLimiter rt = new RateLimiter.create(2);
System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire());
Çıktı olarak şunu alırız
0.0
0.498957
0.497851
0.499391
0.499364
Örnek
Elimizde şöyle bir kod olsun. Saniyede 2 istek işler.
RateLimiter rl = RateLimiter.create(2);
System.out.println(rl.getRate());
System.out.println(rl.tryAcquire());
System.out.println(rl.tryAcquire());
System.out.println(rl.tryAcquire());
Çıktı olarak şunu alırız. İkinci istek false döner çünkü istekleri eşit dağıtmaya çalışır.
2.0
true
false
false
create metodu - SmoothWarmingUp
İmzası şöyle
static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit)
Metod altta şöyledir.
static RateLimiter create(SleepingStopwatch stopwatch, double permitsPerSecond,
long warmupPeriod, TimeUnit unit, double coldFactor) {

  RateLimiter rateLimiter = new SmoothWarmingUp(stopwatch, warmupPeriod, unit,
coldFactor);
  rateLimiter.setRate(permitsPerSecond);
  return rateLimiter;
}
Açıklaması şöyle
The RateLimiterSmoothWarmingUp method has a warm-up period after the startup. It gradually increases the distribution rate to the configured value.

For example, you can use the following snippet to create a ratelimiter with an average token creation rate of 2 tokens/s, and a warm-up period of 3 seconds. The token bucket does not create a token every 0.5 seconds immediately after startup, because a warm-up period of 3 seconds has been set. Instead, the system gradually increases the token creation rate to the pre-set value within 3 seconds and then creates tokens at a fixed rate. This feature is suitable for scenarios where the system needs some time to warm up after startup.

RateLimiter r = RateLimiter.create(2, 3, TimeUnit.SECONDS);
Örnek
Elimizde şöyle bir kod olsun. RateLimiter dolu başlar. 4 saniye boyunca yavaştır yani ısınır. Isınması gittikçe daha hızlanarak sürer. 4 saniye sonunda normal hızında yani saniyede 2 tane token üretmeye başlar.
RateLimiter rt = new RateLimiter.create(2,4, TimeUnit.SECONDS);
System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire()); System.out.println(rt.acquire());
Çıktı olarak şunu alırız
0.0
1.3743
1.123576
0.874151
0.624409 
0.50001
tryAcquire metodu
Şöyle yaparız.
while (true) {
  
  if (rateLimiter.tryAcquire()) {
    ...
  }
}

12 Haziran 2019 Çarşamba

InetAddresses Sınıfı

Giriş
Bu sınıf JDK'daki InetAddress sınıfını tamamlıyor ile IP adresleri ile çalışmayı daha da kolaylaştırıyor.

isInetAddress metodu
Verilen parametrenin nokta ile ayrılmış IP string adresi olup olmadığı kontrol eder.