Skip to content

Commit

Permalink
Merge pull request #232 from MaxBartkov/fix_grammar_asciidoc
Browse files Browse the repository at this point in the history
Fix grammar asciidoc
  • Loading branch information
vladimir-bukhtoyarov committed Feb 10, 2022
2 parents 4c05160 + f0be6a9 commit 3c362f1
Show file tree
Hide file tree
Showing 42 changed files with 320 additions and 324 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -39,7 +39,7 @@ The Bucket4j is distributed through [Maven Central](http://search.maven.org/):
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>7.2.0</version>
<version>7.3.0</version>
</dependency>
```
#### You can build Bucket4j from sources
Expand Down
2 changes: 1 addition & 1 deletion asciidoc/pom.xml
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-parent</artifactId>
<version>7.2.0</version>
<version>7.3.0</version>
<relativePath>../bucket4j-parent</relativePath>
</parent>
<artifactId>asciidoc</artifactId>
Expand Down
28 changes: 14 additions & 14 deletions asciidoc/src/main/docs/asciidoc/about.adoc
@@ -1,29 +1,29 @@
== About Bucket4j
=== What is Bucket4j
Bucket4j is Java rate-limiting library is mainly based on token-bucket algorithm, which are by de-facto standard for rate limiting in the IT industry.
Bucket4j is a Java rate-limiting library that is mainly based on the token-bucket algorithm, which is by the de-facto standard for rate-limiting in the IT industry.

.Bucket4j is more than direct implementation of token-bucket
.Bucket4j is more than a direct implementation of token-bucket
IMPORTANT: Its math model provides several useful extensions that are not mentioned in the classic token-bucket interpretations, such as multiple limits per bucket or overdraft. These math extensions will be detailed described later.

You can read more about token bucket by following links:
You can read more about the token bucket by following links:

* https://en.wikipedia.org/wiki/Token_bucket[Token bucket] - wikipedia page describes the token-bucket algorithm in classical form.
* https://vbukhtoyarov-java.blogspot.com/2021/11/non-formal-overview-of-token-bucket.html[Non-formal overview of token-bucket algorithm] - the brief overview of token-bucket algorithm.
* https://en.wikipedia.org/wiki/Token_bucket[Token bucket] - Wikipedia page describes the token-bucket algorithm in classical form.
* https://vbukhtoyarov-java.blogspot.com/2021/11/non-formal-overview-of-token-bucket.html[Non-formal overview of token-bucket algorithm] - the brief overview of the token-bucket algorithm.

=== Bucket4j basic features
* *Absolutely non-compromise precision* - Bucket4j does not operate with floats or doubles, all calculation are performed in the integer arithmetic, this feature protects end users from calculation errors involved by rounding.
* *Absolutely non-compromise precision* - Bucket4j does not operate with floats or doubles, all calculations are performed in integer arithmetic, this feature protects end-users from calculation errors involved by rounding.
* *Effective implementation in terms of concurrency*:
- Bucket4j is good scalable for multi-threading case it by defaults uses lock-free implementation.
- In same time, library provides different concurrency strategies that can be chosen when default lock-free strategy is not desired.
- Bucket4j is good scalable for multi-threading cases it by default uses lock-free implementation.
- At the same time, the library provides different concurrency strategies that can be chosen when a default lock-free strategy is not desired.
* *Effective API in terms of garbage collector footprint*: Bucket4j API tries to use primitive types as much as it is possible in order to avoid boxing and other types of floating garbage.
* *Pluggable listener API* that allows to implement monitoring and logging.
* *Rich diagnostic API* that allows to investigate internal state.
* *Rich configuration management* - configuration of the bucket can be changed on fly
* *Pluggable listener API* that allows implementing monitoring and logging.
* *Rich diagnostic API* that allows investigating internal state.
* *Rich configuration management* - configuration of the bucket can be changed on the fly

=== Bucket4j distributed features
In additional to basic features described above, `Bucket4j` provides ability to implement rate-limiting in cluster of JVMs:
In addition to the basic features described above, `Bucket4j` provides the ability to implement rate-limiting in a cluster of JVMs:

* Bucket4j out of the box supports any GRID solution which compatible with JCache API (JSR 107) specification.
* Bucket4j provides the framework that allows to quickly build integration with your own persistent technology like RDMS or a key-value storage.
* For clustered usage scenarios Bucket4j supports asynchronous API that extremely matters when going to distribute world, because asynchronous API allows avoiding blocking your application threads each time when you need to execute Network request.
* Bucket4j provides the framework that allows you to quickly build integration with your own persistent technology like RDMS or key-value storage.
* For clustered usage scenarios Bucket4j supports asynchronous API that extremely matters when going to distribute world because asynchronous API allows avoiding blocking your application threads each time when you need to execute Network request.

@@ -1,15 +1,15 @@
[[configuration-replacement]]
=== On-the-fly configuration replacement
As previously mentioned in the definition for <<bucket-bonfiguration>> it is immutable object.
It is not possible to add, remove or change the limits for already created configuration, however, you can replace configuration of bucket via creating new configuration instance and calling `bucket.replaceConfiguration(newConfiguration, tokensInheritanceStrategy)`.
As previously mentioned in the definition for <<bucket-bonfiguration>> it is an immutable object.
It is not possible to add, remove or change the limits for already created configuration, however, you can replace the configuration of the bucket via creating a new configuration instance and calling `bucket.replaceConfiguration(newConfiguration, tokensInheritanceStrategy)`.

==== Why configuration replacement is not trivial?
1. The first problem of configuration replacement is making decision how to propagate available tokens from bucket with previous configuration to bucket with new configuration. If you don't care about previous bucket state then use `TokensInheritanceStrategy.RESET`. But it becomes to a tricky problem when we expect that previous consumption(that has not been compensated by refill yet) should take effect to the bucket with new configuration. In this case you need to make a choice between:
1. The first problem of configuration replacement is deciding on how to propagate available tokens from a bucket with a previous configuration to the bucket with a new configuration. If you don't care about previous the bucket state then use `TokensInheritanceStrategy.RESET`. But it becomes a tricky problem when we expect that previous consumption(that has not been compensated by refill yet) should take effect on the bucket with a new configuration. In this case, you need to choose between:
* <<tokens-inheritance-strategy-proportionally, TokensInheritanceStrategy.PROPORTIONALLY>>
* <<tokens-inheritance-strategy-as-is, TokensInheritanceStrategy.AS_IS>>
* <<tokens-inheritance-strategy-additive, TokensInheritanceStrategy.ADDITIVE>>

2. There is another problem when you are choosing <<tokens-inheritance-strategy-proportionally, PROPORTIONALLY>>, <<tokens-inheritance-strategy-as-is, AS_IS>> or <<tokens-inheritance-strategy-additive, ADDITIVE>> or <<tokens-inheritance-strategy-as-is, AS_IS>> and bucket has more then one bandwidth. For example how does replaceConfiguration implementation should bind bandwidths to each other in the following example?
2. There is another problem when you are choosing <<tokens-inheritance-strategy-proportionally, PROPORTIONALLY>>, <<tokens-inheritance-strategy-as-is, AS_IS>> or <<tokens-inheritance-strategy-additive, ADDITIVE>> or <<tokens-inheritance-strategy-as-is, AS_IS>> and a bucket has more than one bandwidth. For example, how does replaceConfiguration implementation bind bandwidths to each other in the following example?
[source, java]
----
Bucket bucket = Bucket.builder()
Expand All @@ -23,11 +23,11 @@ BucketConfiguration newConfiguration = BucketConfiguration.configurationBuilder(
.build();
bucket.replaceConfiguration(newConfiguration, TokensInheritanceStrategy.AS_IS);
----
It is obviously that simple strategy - copying tokens by bandwidth index will not work well in this case, because of it highly depends on order in which bandwidths were mentioneed in new and previous configuration.
It is obvious that a simple strategy - copying tokens by bandwidth index will not work well in this case, because it highly depends on the order in which bandwidths were mentioned in the new and previous configuration.

==== Taking control over replacement process via bandwidth identifiers
Instead of inventing the backward maggic Bucket4j provides to you ability to deap controll of this process by specifying identifiers for bandwidth,
so in case of multiple bandwidth configuratoin replacement code can copy available tokens by bandwidth ID. So it is better to rewrite code above as following:
Instead of inventing the backward magic Bucket4j provides you the ability to keep control this process by specifying identifiers for bandwidth,
so in case of multiple bandwidth configuration replacement codes can copy available tokens by bandwidth ID. So it is better to rewrite the code above as follows:
[source, java]
----
Bucket bucket = Bucket.builder()
Expand All @@ -41,10 +41,10 @@ Bucket bucket = Bucket.builder()
.build();
bucket.replaceConfiguration(newConfiguration, TokensInheritanceStrategy.PROPORTIONALLY);
----
.There are following rules for bandwidth identifiers:
.There are the following rules for bandwidth identifiers:
* By default bandwidth has <b>null</b> identifier.
* null value of identifier equals to another null value if and only if there is only one bandwidth with null identifier.
* If identifier for bandwidth is specified then it must has unique in the bucket. Bucket does not allow to create several bandwidth with same ID.
* null value of identifier equals to another null value if and only if there is only one bandwidth with a null identifier.
* If an identifier for bandwidth is specified then it must be unique in the bucket. Bucket does not allow to create of several bandwidths with the same ID.

==== TokensInheritanceStrategy explanation
*TokensInheritanceStrategy* specifies the rules for inheritance of available tokens during configuration replacement process.
Expand All @@ -56,31 +56,31 @@ Makes to copy available tokens proportional to bandwidth capacity by following f
.PROPORTIONALLY strategy examples:
** *Example 1:* imagine bandwidth that was created by `Bandwidth.classic(100, Refill.gready(10, Duration.ofMinutes(1)))`. +
+
At the moment of config replacement it was 40 available tokens. +
At the moment of config replacement, there were 40 available tokens. +
+
After replacing this bandwidth by following `Bandwidth.classic(200, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens will be multiplied by 2(200/100), and after replacement we will have 80 available tokens.
After replacing this bandwidth by following `Bandwidth.classic(200, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens will be multiplied by 2(200/100), and after replacement, we will have 80 available tokens.

** *Example 2:* imagine bandwidth that was created by `Bandwidth.classic(100, Refill.gready(10, Duration.ofMinutes(1)))`.
At the moment of config replacement it was 40 available tokens. After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens will be multiplied by 0.2(20/100), and after replacement we will have 8 available tokens.
At the moment of config replacement, there were 40 available tokens. After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens will be multiplied by 0.2(20/100), and after replacement, we will have 8 available tokens.

AS_IS::
Instructs to copy available tokens as is, but with one exclusion: if available tokens is greater than new capacity, available tokens will be decreased to new capacity.
Instructs to copy available tokens as is, but with one exclusion: if available tokens are greater than new capacity, available tokens will be decreased to new capacity.
+
.AS_IS strategy examples:
** *Example 1:* imagine bandwidth that was created by `Bandwidth.classic(100, Refill.gready(10, Duration.ofMinutes(1)))`. +
+
At the moment of config replacement it was 40 available tokens. +
At the moment of config replacement, it was 40 available tokens. +
+
After replacing this bandwidth by following `Bandwidth.classic(200, Refill.gready(10, Duration.ofMinutes(1)))}` 40 available tokens will be just copied, and after replacement we will have 40 available tokens.
After replacing this bandwidth by following `Bandwidth.classic(200, Refill.gready(10, Duration.ofMinutes(1)))}` 40 available tokens will be just copied, and after replacement, we will have 40 available tokens.

** *Example 2:* imagine bandwidth that was created by `Bandwidth.classic(100, Refill.gready(10, Duration.ofMinutes(1)))`. +
+
At the moment of config replacement it was 40 available tokens. +
At the moment of config replacement, it was 40 available tokens. +
+
After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens can not be copied as is, because it is greater than new capacity, so available tokens will be reduced to 20.
After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens can not be copied as is because it is greater than new capacity, so available tokens will be reduced to 20.

RESET::
Use this mode when you want just to forget about previous bucket state. RESET just instructs to erases all previous state. Using this strategy equals to removing bucket and creating again with new configuration.
Use this mode when you want just to forget about the previous bucket state. RESET just instructs to erase all previous states. Using this strategy equals removing a bucket and creating again with a new configuration.

ADDITIVE::
Instructs to copy available tokens as is, but with one exclusion: if new bandwidth capacity is greater than old capacity, available tokens will be increased by the difference between the old and the new configuration. +
Expand All @@ -93,17 +93,17 @@ Instructs to copy available tokens as is, but with one exclusion: if new bandwid
+
At the moment of configuration replacement, it was 40 available tokens. +
+
After replacing this bandwidth by following `Bandwidth.classic(200, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens will be copied and added to the difference between old and new configuration, and after replacement, we will have 140 available tokens.
After replacing this bandwidth by following `Bandwidth.classic(200, Refill.gready(10, Duration.ofMinutes(1)))` 40 available tokens will be copied and added to the difference between old and new configurations, and after replacement, we will have 140 available tokens.

** *Example 2:* imagine bandwidth that was created by `Bandwidth.classic(100, Refill.gready(10, Duration.ofMinutes(1)))`. +
+
At the moment of config replacement it was 40 available tokens. +
At the moment of config replacement, it was 40 available tokens. +
+
After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1))))`,
and after replacement we will have 20 available tokens.

** *Example 3:* imagine bandwidth that was created by `Bandwidth.classic(100, Refill.gready(10, Duration.ofMinutes(1)))`. +
+
At the moment of config replacement it was 10 available tokens.
At the moment of config replacement, it was 10 available tokens.
+
After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1))))`, and after replacement we will have 10 available tokens.
After replacing this bandwidth by following `Bandwidth.classic(20, Refill.gready(10, Duration.ofMinutes(1))))`, and after replacement, we will have 10 available tokens.

0 comments on commit 3c362f1

Please sign in to comment.