Ivan, thanks for the link. I think, now I've got what you mean. I don't think we want to have any framework as a dependency and rely on their lifecycle, roadmaps goals and bother about compatibility. JDK classes are well-known and reactive frameworks usually have converters to/from CompletableFuture [1] [2]. So, users are free to choose any reactive framework.
I think will need reactive abstractions in near future for Queries API and maybe Transaction API design. These projects are good enough where we can get inspiration. [1] https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#fromFuture-java.util.concurrent.CompletableFuture- [2] https://github.com/ReactiveX/RxJava/blob/3.x/src/main/java/io/reactivex/rxjava3/internal/jdk8/CompletableFromCompletionStage.java On Thu, Apr 1, 2021 at 1:29 PM Ivan Pavlukhin <vololo...@gmail.com> wrote: > Andrey, > > > Reactive abstractions look more suitable for Queries rather than > > cache/table async operations and don't offer the power of chaining like > > CompletableStage. > > Could you please elaborate what capabilities do you mean? AFAIK there > are quite powerful APIs for singular reactive abstractions as well. > E.g. [1]. > > [1] > https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html > > 2021-04-01 12:33 GMT+03:00, Andrey Mashenkov <andrey.mashen...@gmail.com>: > > Val, > > I just complain JDK CompletableFuture itself is not ideal, but already > > implemented, well-known and tested. > > It still a good alternative compared to custom future implementation to > me. > > > > Ok, I feel most of us agree with CompletableFuture as a replacement for > > custom IgniteFuture. > > Let's try to use it, but keep in mind that we MUST return a defective > copy > > (via copy() or minimalStage()) to user to prevent misusage on the user > > side. > > It would be nice if we'll follow the same requirement in our internal > code, > > e.g. if a component returns a future that further can be used in other > > components, especially in custom plugins. > > > > Ivan, thanks for the example. > > Reactive abstractions look more suitable for Queries rather than > > cache/table async operations and don't offer the power of chaining like > > CompletableStage. > > AFAIK, guys who involved in SQL engine development based on Calcite > already > > use reactive patterns. > > > > > > On Thu, Apr 1, 2021 at 3:15 AM Ivan Pavlukhin <vololo...@gmail.com> > wrote: > > > >> Folks, > >> > >> Regarding Reactive abstractions. While it might look too complex for > >> simple KV cases it can be quite powerful for queries. Also there are > >> known solutions for cancellation, backpressure and flow control. It > >> can greatly simplify things for users familiar with Reactive > >> programming rather than learning Ignite-specific Query/QueryCursor > >> API. > >> > >> Also it looks like there are well-defined semantics [1]. E.g. > >> cancellation seems to be defined much better than for > >> CompletableFuture. > >> > >> [1] > >> https://github.com/reactive-streams/reactive-streams-jvm#specification > >> > >> 2021-03-31 21:30 GMT+03:00, Valentin Kulichenko < > >> valentin.kuliche...@gmail.com>: > >> > Hi Andrey, > >> > > >> > Please see below. > >> > > >> > -Val > >> > > >> > On Wed, Mar 31, 2021 at 7:55 AM Andrey Mashenkov > >> > <andrey.mashen...@gmail.com> > >> > wrote: > >> > > >> >> CompletableFuture cancellation will not work as many users expected. > >> >> Javadoc says: > >> >> /* Since (unlike {@link FutureTask}) this class has no direct > >> >> * control over the computation that causes it to be completed, > >> >> * cancellation is treated as just another form of exceptional > >> >> * completion. > >> >> */ > >> >> > >> > > >> > Let's not make assumptions about the expectations of the users. That's > >> > exactly why I initially leaned towards a custom interface as well, but > >> > that's a mistake. > >> > Indeed, this contract might look weird to us, because the current > >> > version > >> > of Ignite behaves differently. However, there are much more developers > >> > using CompletableFuture and other standard async frameworks, than > >> > developers using the async functionality of Ignite. Therefore, our > >> > intuitions can easily be wrong. > >> > > >> > > >> >> Completion of a child future doesn't trigger the completion of a > >> >> parent. > >> >> So, we will need to extend the future anyway. > >> >> > >> > > >> > First of all, as Pavel mentioned, you can attach your own listener > >> > before > >> > returning a CompletableFuture to the user. You don't need to extend. > >> > Second of all, there is still a discussion to be had on whether the > >> parent > >> > needs to be completed. I don't actually think it's obvious, and most > >> likely > >> > it's case by case. With CompletableFuture you have enough flexibility > >> > to > >> > control the behavior. > >> > > >> > > >> >> > >> >> Also, cancel() method contract differs from IgniteFuture in 2.0, > >> >> Completable method return true if the future was cancelled, > >> >> but IgniteFuture return true only if it wasn't cancel prior the call. > >> >> Thus, if cancel() was called twice we will have different results for > >> >> CompletableFuture and IgniteFuture, > >> >> that makes CompletableFuture barely usable for our internal purposes. > >> >> > >> > > >> > It doesn't really matter how IgniteFuture in 2.0 behaves. It was > >> > created > >> > long before continuations and other async concepts became mainstream > >> > (in > >> > Java world at least). > >> > Also, we don't have to use it for internal purposes, of course. I'm > >> > only > >> > talking about public APIs. > >> > > >> > > >> >> > >> >> BTW, CompletableFuture.anyOf() still can be used, see > >> >> CompletionStage.toCompletableFuture() contract. > >> >> > >> > > >> > In my view, this actually kills the idea of a custom future. > Basically, > >> > the proposal is to introduce a custom entity to restrict access to > some > >> of > >> > the CompletableFuture methods, but then allow to convert this custom > >> entity > >> > to a CompletableFuture that has all the methods. This makes zero sense > >> > to > >> > me. > >> > > >> > > >> >> > >> >> The more I learn about CompletableFuture the stronger my opinion > about > >> >> overriding it. > >> >> > >> >> > >> >> On Wed, Mar 31, 2021 at 9:31 AM Denis Garus <garus....@gmail.com> > >> wrote: > >> >> > >> >> > > Stripping them from such functionality, which they are used to, > is > >> >> > > most > >> >> > likely a bad idea. > >> >> > > >> >> > Completely agree with this point of view. > >> >> > Moreover, a user can pass CompletableFuture to another library to > do > >> >> > any > >> >> > manipulations. > >> >> > So if we want to introduce our class instead of the java class, we > >> >> > should > >> >> > have solid arguments; > >> >> > otherwise, it can be a reason for irritation. > >> >> > > >> >> > ср, 31 мар. 2021 г. в 09:06, Pavel Tupitsyn <ptupit...@apache.org > >: > >> >> > > >> >> > > Val, > >> >> > > > >> >> > > > we can have an IgniteFuture that extends CompletableFuture. > >> >> > > > This might be useful if want the cancel() operation to cancel > >> >> > > > the > >> >> > > > underlying operation > >> >> > > > >> >> > > I think we can subscribe to the cancellation of the > >> CompletableFuture > >> >> > > and cancel the underlying operation without an extra class, > >> >> > > something like > >> >> > > > >> >> > > fut.exceptionally(t -> { > >> >> > > if (t instanceof CancellationException) { > >> >> > > // Cancel Ignite operation > >> >> > > } > >> >> > > }); > >> >> > > > >> >> > > On Wed, Mar 31, 2021 at 7:45 AM Valentin Kulichenko < > >> >> > > valentin.kuliche...@gmail.com> wrote: > >> >> > > > >> >> > > > These are actually some interesting points. As I'm thinking > more > >> >> about > >> >> > > > this, I'm leaning towards changing my opinion and voting for > the > >> >> > > > CompletableFuture. Here is my reasoning. > >> >> > > > > >> >> > > > First, it's important to keep in mind that CompletableFuture is > >> not > >> >> an > >> >> > > > interface that we will implement, it's an implemented class. > >> >> Therefore, > >> >> > > > some of the concerns around complete() and cancel() method are > >> >> > > > not > >> >> > really > >> >> > > > relevant -- it's not up to us how these methods behave, they're > >> >> already > >> >> > > > implemented. > >> >> > > > > >> >> > > > Second, CompletableFuture does provide some useful > functionality > >> >> (anyOf > >> >> > > is > >> >> > > > one of the examples). I can even envision users wanting to > >> complete > >> >> the > >> >> > > > future under certain circumstances, e.g. after a timeout, using > >> >> > > > the completeOnTimeout method. Stripping them from such > >> >> > > > functionality, > >> >> > > which > >> >> > > > they are used to, is most likely a bad idea. > >> >> > > > > >> >> > > > And finally, we can have an IgniteFuture that extends > >> >> > CompletableFuture. > >> >> > > > This might be useful if want the cancel() operation to cancel > >> >> > > > the > >> >> > > > underlying operation. This way we keep all the functionality of > >> >> > > > CompletableFuture while keeping a certain amount of flexibility > >> for > >> >> > > > specific cases. > >> >> > > > > >> >> > > > Thoughts? > >> >> > > > > >> >> > > > -Val > >> >> > > > > >> >> > > > > >> >> > > > On Tue, Mar 30, 2021 at 5:36 AM Denis Garus > >> >> > > > <garus....@gmail.com> > >> >> > wrote: > >> >> > > > > >> >> > > > > > Completing future from outside will never respect other > >> >> subscribers > >> >> > > > that > >> >> > > > > > may expect other guatantees. > >> >> > > > > > >> >> > > > > For example, if we talk about public API like IgniteCache, > >> >> > > > > what > >> >> > > > subscribers > >> >> > > > > may expect other guatantees? > >> >> > > > > IMHO, the best solution is to get the well-known standard > >> >> > > > > interface > >> >> > to > >> >> > > a > >> >> > > > > user, and he will be happy. > >> >> > > > > > >> >> > > > > But when we talk about internal classes like "exchange > future" > >> >> > > > > they > >> >> > > could > >> >> > > > > be custom futures if convenient. > >> >> > > > > > >> >> > > > > вт, 30 мар. 2021 г. в 15:25, Atri Sharma <a...@apache.org>: > >> >> > > > > > >> >> > > > > > IMO the only way Ignite should cancel computations is iff > >> >> > > > > > cancel > >> >> > > method > >> >> > > > > is > >> >> > > > > > invoked, not implicitly if complete is invoked. > >> >> > > > > > > >> >> > > > > > On Tue, 30 Mar 2021 at 4:58 PM, Denis Garus > >> >> > > > > > <garus....@gmail.com > >> >> > > >> >> > > > wrote: > >> >> > > > > > > >> >> > > > > > > Hello! > >> >> > > > > > > > >> >> > > > > > > > Let's say a user started a compute with fut = > >> >> > > > compute.runAsync(task); > >> >> > > > > > > > and now calls fut.complete(someVal); Does this mean > that > >> >> Ignite > >> >> > > no > >> >> > > > > > longer > >> >> > > > > > > needs to execute the task? > >> >> > > > > > > > If the task is currently running, does it need to be > >> >> canceled? > >> >> > > > > > > > >> >> > > > > > > Yes, this case looks like Ignite should cancel > >> >> > > > > > > computations > >> >> > > because a > >> >> > > > > > user > >> >> > > > > > > wants to complete the future. Why not? > >> >> > > > > > > If there will be an opportunity to cancel a future, why > is > >> it > >> >> > > > > > > a > >> >> > bad > >> >> > > > > > option > >> >> > > > > > > to finish a future through a complete() method? > >> >> > > > > > > > >> >> > > > > > > > If you look at Ignite-2 code, you may found a number of > >> >> places > >> >> > > > where > >> >> > > > > we > >> >> > > > > > > return e.g. exchange futures or partition release > futures. > >> >> > > > > > > > Assume the impact if we will return CompletableFuture > >> >> instead, > >> >> > > > which > >> >> > > > > > can > >> >> > > > > > > be completed in 3-rd party plugin by mistake? > >> >> > > > > > > > >> >> > > > > > > If exchange futures or partition release futures can be > >> >> returned > >> >> > to > >> >> > > > > 3-rd > >> >> > > > > > > party plugin by mistake, it is poor encapsulation. > >> >> > > > > > > And if it will be IgniteFuter rather than > CompletedFuture, > >> >> > anyway, > >> >> > > > this > >> >> > > > > > can > >> >> > > > > > > harm. > >> >> > > > > > > > >> >> > > > > > > вт, 30 мар. 2021 г. в 13:14, Andrey Mashenkov < > >> >> > > > > > andrey.mashen...@gmail.com > >> >> > > > > > > >: > >> >> > > > > > > > >> >> > > > > > > > Guys, > >> >> > > > > > > > > >> >> > > > > > > > I want to remember there is one more point to pay > >> attention > >> >> to. > >> >> > > > > > > > Extending Future and CompletableStage is more than just > >> >> > prevents > >> >> > > > > > > unexpected > >> >> > > > > > > > behavior if a user completed the future. > >> >> > > > > > > > > >> >> > > > > > > > First of all, it helps us to write safer code as we > >> >> > > > > > > > won't > >> a > >> >> > > method > >> >> > > > > > > contract > >> >> > > > > > > > exposed such methods as to a user as to a developer. > >> >> > > > > > > > If you look at Ignite-2 code, you may found a number of > >> >> places > >> >> > > > where > >> >> > > > > we > >> >> > > > > > > > return e.g. exchange futures or partition release > >> >> > > > > > > > futures. > >> >> > > > > > > > Assume the impact if we will return CompletableFuture > >> >> instead, > >> >> > > > which > >> >> > > > > > can > >> >> > > > > > > be > >> >> > > > > > > > completed in 3-rd party plugin by mistake? > >> >> > > > > > > > > >> >> > > > > > > > The suggested approach allows us to don't bother if a > >> >> > > > > CompletableFuture > >> >> > > > > > > has > >> >> > > > > > > > to be wrapped or not. > >> >> > > > > > > > > >> >> > > > > > > > > >> >> > > > > > > > On Tue, Mar 30, 2021 at 12:22 PM Alexey Goncharuk < > >> >> > > > > > > > alexey.goncha...@gmail.com> wrote: > >> >> > > > > > > > > >> >> > > > > > > > > Ivan, > >> >> > > > > > > > > > >> >> > > > > > > > > My concern with the concept of a user completing the > >> >> > > > > > > > > future > >> >> > > > > returned > >> >> > > > > > > from > >> >> > > > > > > > > Ignite public API is that it is unclear how to > >> >> > > > > > > > > interpret > >> >> this > >> >> > > > > action > >> >> > > > > > > > (this > >> >> > > > > > > > > backs Val's message). > >> >> > > > > > > > > Let's say a user started a compute with fut = > >> >> > > > > compute.runAsync(task); > >> >> > > > > > > and > >> >> > > > > > > > > now calls fut.complete(someVal); Does this mean that > >> >> > > > > > > > > Ignite > >> >> > no > >> >> > > > > longer > >> >> > > > > > > > needs > >> >> > > > > > > > > to execute the task? If the task is currently > running, > >> >> > > > > > > > > does > >> >> > it > >> >> > > > need > >> >> > > > > > to > >> >> > > > > > > be > >> >> > > > > > > > > canceled? > >> >> > > > > > > > > > >> >> > > > > > > > > Using CompletableFuture.anyOf() is a good instrument > >> >> > > > > > > > > in > >> >> this > >> >> > > case > >> >> > > > > > > because > >> >> > > > > > > > > it makes the 'first future wins' contract explicit in > >> the > >> >> > code. > >> >> > > > > > Besides > >> >> > > > > > > > > that, the point regarding the cancel() method is > >> >> > > > > > > > > valid, > >> >> > > > > > > > > and > >> >> > we > >> >> > > > will > >> >> > > > > > > need > >> >> > > > > > > > > some custom mechanics to cancel a computation, so a > >> >> > > > > > > > > custom > >> >> > > > > interface > >> >> > > > > > > that > >> >> > > > > > > > > simply extends both Future and CompletableStage seems > >> >> > > reasonable > >> >> > > > to > >> >> > > > > > me. > >> >> > > > > > > > > > >> >> > > > > > > > > --AG > >> >> > > > > > > > > > >> >> > > > > > > > > пн, 29 мар. 2021 г. в 09:12, Ivan Pavlukhin < > >> >> > > vololo...@gmail.com > >> >> > > > >: > >> >> > > > > > > > > > >> >> > > > > > > > > > Val, > >> >> > > > > > > > > > > >> >> > > > > > > > > > There were enough hype around Reactive programming > >> past > >> >> > > years. > >> >> > > > I > >> >> > > > > > > > > > remind a lot of talks about RxJava. And I suppose > it > >> >> worth > >> >> > to > >> >> > > > > > > consider > >> >> > > > > > > > > > it. But it requires some time to study modern > trends > >> to > >> >> > make > >> >> > > a > >> >> > > > > > > choice. > >> >> > > > > > > > > > So far I am not ready to facilitate Reactive API > for > >> >> Ignite > >> >> > > 3. > >> >> > > > > > > > > > > >> >> > > > > > > > > > Regarding CompletableFuture. > >> >> > > > > > > > > > > >> >> > > > > > > > > > > The point is that currently a future returned > from > >> >> > > > > > > > > > > any > >> >> of > >> >> > > > > > Ignite's > >> >> > > > > > > > > async > >> >> > > > > > > > > > > operations is supposed to be completed with a > >> >> > > > > > > > > > > value > >> >> only > >> >> > by > >> >> > > > > > Ignite > >> >> > > > > > > > > > itself, > >> >> > > > > > > > > > > not by the user. If we follow the same approach > in > >> >> Ignite > >> >> > > 3, > >> >> > > > > > > > returning > >> >> > > > > > > > > > > CompletableFuture is surely wrong in my view. > >> >> > > > > > > > > > > >> >> > > > > > > > > > My first thoughts was similar. But later I thought > >> what > >> >> > > > > > > > > > a > >> >> > > user > >> >> > > > > > would > >> >> > > > > > > > > > like do with returned future. And one of cases I > >> >> > > > > > > > > > imagined > >> >> > > was a > >> >> > > > > > case > >> >> > > > > > > > > > of alternative result. E.g. a user uses Ignite and > >> >> another > >> >> > > data > >> >> > > > > > > source > >> >> > > > > > > > > > in his application. He wants to use a value arrived > >> >> faster. > >> >> > > He > >> >> > > > > > > > > > combines 2 futures like > >> >> > > > > > > > > > CompletableFuture.anyOf(...). > >> >> > > > > Consequently > >> >> > > > > > > > > > even if we prohibit CompletableFuture.complete(...) > >> >> > > explicitly > >> >> > > > > then > >> >> > > > > > > it > >> >> > > > > > > > > > will be possible to create a combination that will > >> >> > > > > > > > > > allow > >> >> > > > > premature > >> >> > > > > > > > > > future completion. After all generally > >> >> > > > > > > > > > CompletableFuture > >> >> > is a > >> >> > > > > > > > > > placeholder for async computaion result and if a > >> >> > > > > > > > > > user > >> >> wants > >> >> > > to > >> >> > > > > > > > > > substitute result returned from Ignite why should > we > >> >> > disallow > >> >> > > > him > >> >> > > > > > to > >> >> > > > > > > > > > do it? > >> >> > > > > > > > > > > >> >> > > > > > > > > > Also I found one more suspicious thing with > >> >> > > CompletableFuture. > >> >> > > > As > >> >> > > > > > it > >> >> > > > > > > > > > is a concrete class it implements a cancel() > method. > >> >> > > > > > > > > > And > >> >> > as I > >> >> > > > see > >> >> > > > > > the > >> >> > > > > > > > > > implementation does not try to cancel underlying > >> >> > > computations. > >> >> > > > Is > >> >> > > > > > not > >> >> > > > > > > > > > it a problem? > >> >> > > > > > > > > > > >> >> > > > > > > > > > 2021-03-29 7:30 GMT+03:00, Valentin Kulichenko < > >> >> > > > > > > > > > valentin.kuliche...@gmail.com>: > >> >> > > > > > > > > > > Ivan, > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > It's not really about the "harm", but more about > >> >> > > > > > > > > > > "what > >> >> > > should > >> >> > > > > we > >> >> > > > > > do > >> >> > > > > > > > if > >> >> > > > > > > > > > this > >> >> > > > > > > > > > > method is called?". Imagine the following code: > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > CompletableFuture<String> fut = > >> >> > > > > > > > > > > cache.getAsync(key); > >> >> > > > > > > > > > > fut.complete("something"); > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > What should happen in this case? > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > The point is that currently a future returned > from > >> >> > > > > > > > > > > any > >> >> of > >> >> > > > > > Ignite's > >> >> > > > > > > > > async > >> >> > > > > > > > > > > operations is supposed to be completed with a > >> >> > > > > > > > > > > value > >> >> only > >> >> > by > >> >> > > > > > Ignite > >> >> > > > > > > > > > itself, > >> >> > > > > > > > > > > not by the user. If we follow the same approach > in > >> >> Ignite > >> >> > > 3, > >> >> > > > > > > > returning > >> >> > > > > > > > > > > CompletableFuture is surely wrong in my view. > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > At the same time, if we take a fundamentally > >> >> > > > > > > > > > > different > >> >> > > route > >> >> > > > > with > >> >> > > > > > > the > >> >> > > > > > > > > > async > >> >> > > > > > > > > > > APIs, this whole discussion might become > >> >> > > > > > > > > > > irrelevant. > >> >> For > >> >> > > > > example, > >> >> > > > > > > can > >> >> > > > > > > > > you > >> >> > > > > > > > > > > elaborate on your thinking around the reactive > >> >> > > > > > > > > > > API? > >> >> > > > > > > > > > > Do > >> >> > you > >> >> > > > have > >> >> > > > > > any > >> >> > > > > > > > > > > specifics in mind? > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > -Val > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > On Sat, Mar 27, 2021 at 9:18 PM Ivan Pavlukhin < > >> >> > > > > > > vololo...@gmail.com> > >> >> > > > > > > > > > wrote: > >> >> > > > > > > > > > > > >> >> > > > > > > > > > >> > The methods below shouldn't be accessible for > >> >> > > > > > > > > > >> > user: > >> >> > > > > > > > > > >> > complete() > >> >> > > > > > > > > > >> > completeExceptionaly() > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > >> Folks, in case of user-facing API, do you think > >> >> > > > > > > > > > >> there > >> >> > is a > >> >> > > > > real > >> >> > > > > > > harm > >> >> > > > > > > > > > >> in allowing a user to manually "complete" a > >> >> > > > > > > > > > >> future? > >> >> > > > > > > > > > >> I > >> >> > > > suppose > >> >> > > > > a > >> >> > > > > > > user > >> >> > > > > > > > > > >> employs some post-processing for future results > >> >> > > > > > > > > > >> and > >> >> > > > > potentially > >> >> > > > > > > > wants > >> >> > > > > > > > > > >> to have control of these results as well. E.g. > >> >> premature > >> >> > > > > > > completion > >> >> > > > > > > > in > >> >> > > > > > > > > > >> case when a result is no longer needed is > >> >> > > > > > > > > > >> possible > >> >> > usage. > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > >> Also I thinkg it might be a good time to ponder > >> >> > > > > > > > > > >> about > >> >> > > > > > > Future/Promise > >> >> > > > > > > > > > >> APIs in general. Why such API is our choice? Can > >> >> > > > > > > > > > >> we > >> >> > choose > >> >> > > > > e.g. > >> >> > > > > > > > > > >> Reactive API style instead? > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > >> 2021-03-27 0:33 GMT+03:00, Valentin Kulichenko < > >> >> > > > > > > > > > >> valentin.kuliche...@gmail.com>: > >> >> > > > > > > > > > >> > Andrey, > >> >> > > > > > > > > > >> > > >> >> > > > > > > > > > >> > I see. So in a nutshell, you're saying that we > >> >> > > > > > > > > > >> > want > >> >> to > >> >> > > > > return > >> >> > > > > > a > >> >> > > > > > > > > future > >> >> > > > > > > > > > >> that > >> >> > > > > > > > > > >> > the user's code is not allowed to complete. In > >> >> > > > > > > > > > >> > this > >> >> > > case, > >> >> > > > I > >> >> > > > > > > think > >> >> > > > > > > > > it's > >> >> > > > > > > > > > >> > clear that CompletableFuture is not what we > >> >> > > > > > > > > > >> > need. > >> >> > > > > > > > > > >> > We > >> >> > > > > actually > >> >> > > > > > > > need a > >> >> > > > > > > > > > >> > NonCompletableFuture :) > >> >> > > > > > > > > > >> > > >> >> > > > > > > > > > >> > My vote is for the custom interface. > >> >> > > > > > > > > > >> > > >> >> > > > > > > > > > >> > -Val > >> >> > > > > > > > > > >> > > >> >> > > > > > > > > > >> > On Fri, Mar 26, 2021 at 2:25 AM Andrey > >> >> > > > > > > > > > >> > Mashenkov > >> >> > > > > > > > > > >> > <andrey.mashen...@gmail.com> > >> >> > > > > > > > > > >> > wrote: > >> >> > > > > > > > > > >> > > >> >> > > > > > > > > > >> >> Val, > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> The methods below shouldn't be accessible for > >> >> > > > > > > > > > >> >> user: > >> >> > > > > > > > > > >> >> complete() > >> >> > > > > > > > > > >> >> completeExceptionaly() > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> Returning CompletableFuture we must always > >> >> > > > > > > > > > >> >> make > >> a > >> >> > copy > >> >> > > to > >> >> > > > > > > prevent > >> >> > > > > > > > > the > >> >> > > > > > > > > > >> >> original future from being completed by > >> >> > > > > > > > > > >> >> mistake. > >> >> > > > > > > > > > >> >> I think it will NOT be enough to do that > >> returing > >> >> the > >> >> > > > > future > >> >> > > > > > to > >> >> > > > > > > > the > >> >> > > > > > > > > > >> >> end-user, but from every critical module to > >> >> > > > > > > > > > >> >> the > >> >> > outside > >> >> > > > of > >> >> > > > > > the > >> >> > > > > > > > > > module, > >> >> > > > > > > > > > >> >> e.g. to plugins. The impact of disclosing > >> >> > > ExchangeFuture, > >> >> > > > > > > > > > >> >> PartitionReleaseFuture to plugins may be > >> serious. > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> IgniteFuture<T> extends Future<T>, > >> >> CompletionStage<T> > >> >> > > > which > >> >> > > > > > > > > > >> >> implementation > >> >> > > > > > > > > > >> >> will just wrap CompletableFuture these issues > >> >> > > > > > > > > > >> >> will > >> >> be > >> >> > > > > > resolved > >> >> > > > > > > in > >> >> > > > > > > > > > >> natural > >> >> > > > > > > > > > >> >> way. > >> >> > > > > > > > > > >> >> In addition we can force > toCompletableFuture() > >> >> method > >> >> > > to > >> >> > > > > > > return a > >> >> > > > > > > > > > >> >> defensive > >> >> > > > > > > > > > >> >> copy(), that resolves the last concern. > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> On Fri, Mar 26, 2021 at 11:38 AM Konstantin > >> Orlov > >> >> > > > > > > > > > >> >> <kor...@gridgain.com> > >> >> > > > > > > > > > >> >> wrote: > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> > CompletableFuture seems a better option to > >> >> > > > > > > > > > >> >> > me. > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > -- > >> >> > > > > > > > > > >> >> > Regards, > >> >> > > > > > > > > > >> >> > Konstantin Orlov > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > > On 26 Mar 2021, at 11:07, Pavel Tupitsyn > < > >> >> > > > > > > > ptupit...@apache.org > >> >> > > > > > > > > > > >> >> > > > > > > > > > >> >> > > wrote: > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > > On the one hand, I agree with Alexey. > >> >> > > > > > > > > > >> >> > > CompletableFuture has complete* methods > >> which > >> >> > > should > >> >> > > > > not > >> >> > > > > > be > >> >> > > > > > > > > > >> available > >> >> > > > > > > > > > >> >> to > >> >> > > > > > > > > > >> >> > > the user code. > >> >> > > > > > > > > > >> >> > > This can be solved with a simple > interface > >> >> > > > > > > > > > >> >> > > like > >> >> > we > >> >> > > do > >> >> > > > > in > >> >> > > > > > > Thin > >> >> > > > > > > > > > >> Client: > >> >> > > > > > > > > > >> >> > > IgniteClientFuture<T> extends Future<T>, > >> >> > > > > > CompletionStage<T> > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > > On the other hand: > >> >> > > > > > > > > > >> >> > > - CompletionStage has toCompletableFuture > >> >> anyway > >> >> > > > > (rather > >> >> > > > > > > > weird) > >> >> > > > > > > > > > >> >> > > - Other libraries use CompletableFuture > >> >> > > > > > > > > > >> >> > > and > >> >> > > > > > > > > > >> >> > > it > >> >> > > seems > >> >> > > > to > >> >> > > > > > be > >> >> > > > > > > > fine > >> >> > > > > > > > > > >> >> > > - Using CompletableFuture is the simplest > >> >> > approach > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > > So I lean towards CompletableFuture too. > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > > On Fri, Mar 26, 2021 at 10:46 AM Alexey > >> >> > Kukushkin < > >> >> > > > > > > > > > >> >> > kukushkinale...@gmail.com> > >> >> > > > > > > > > > >> >> > > wrote: > >> >> > > > > > > > > > >> >> > > > >> >> > > > > > > > > > >> >> > >> I do not like Java's CompletableFuture > >> >> > > > > > > > > > >> >> > >> and > >> >> > prefer > >> >> > > > our > >> >> > > > > > own > >> >> > > > > > > > > Future > >> >> > > > > > > > > > >> >> > (revised > >> >> > > > > > > > > > >> >> > >> IgniteFuture). > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> My understanding of the Future (or > >> >> > > > > > > > > > >> >> > >> Promise) > >> >> > > pattern > >> >> > > > in > >> >> > > > > > > > general > >> >> > > > > > > > > > is > >> >> > > > > > > > > > >> >> having > >> >> > > > > > > > > > >> >> > >> two separate APIs: > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> 1. Server-side: create, set result, > >> >> > > > > > > > > > >> >> > >> raise > >> >> > error, > >> >> > > > > > cancel > >> >> > > > > > > > from > >> >> > > > > > > > > > >> >> > >> server. > >> >> > > > > > > > > > >> >> > >> 2. Client-side: get result, handle > >> >> > > > > > > > > > >> >> > >> error, > >> >> > cancel > >> >> > > > > from > >> >> > > > > > > > client > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> Java's CompletableFuture looks like both > >> the > >> >> > > > > client-side > >> >> > > > > > > and > >> >> > > > > > > > > > >> >> > >> server-side API. The "Completeable" > >> >> > > > > > > > > > >> >> > >> prefix > >> >> > > > > > > > > > >> >> > >> in > >> >> > the > >> >> > > > name > >> >> > > > > > is > >> >> > > > > > > > > > already > >> >> > > > > > > > > > >> >> > confusing > >> >> > > > > > > > > > >> >> > >> for a client since it cannot "complete" > >> >> > > > > > > > > > >> >> > >> an > >> >> > > > operation, > >> >> > > > > > > only a > >> >> > > > > > > > > > >> >> > >> server > >> >> > > > > > > > > > >> >> can. > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> I would create our own IgniteFuture > >> >> > > > > > > > > > >> >> > >> adding > >> >> > > > client-side > >> >> > > > > > > > > > >> functionality > >> >> > > > > > > > > > >> >> we > >> >> > > > > > > > > > >> >> > >> currently miss (like client-side > >> >> cancellation). > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> пт, 26 мар. 2021 г. в 01:08, Valentin > >> >> > Kulichenko < > >> >> > > > > > > > > > >> >> > >> valentin.kuliche...@gmail.com>: > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >>> Andrey, > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >>> Can you compile a full list of these > >> >> > > > > > > > > > >> >> > >>> risky > >> >> > > methods, > >> >> > > > > and > >> >> > > > > > > > > > >> >> > >>> elaborate > >> >> > > > > > > > > > >> >> > >>> on > >> >> > > > > > > > > > >> >> > what > >> >> > > > > > > > > > >> >> > >>> the risks are? > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >>> Generally, CompletableFuture is a much > >> >> > > > > > > > > > >> >> > >>> better > >> >> > > > option, > >> >> > > > > > > > because > >> >> > > > > > > > > > >> >> > >>> it's > >> >> > > > > > > > > > >> >> > >>> standard. But we need to make sure it > >> >> actually > >> >> > > fits > >> >> > > > > our > >> >> > > > > > > > needs > >> >> > > > > > > > > > >> >> > >>> and > >> >> > > > > > > > > > >> >> > doesn't > >> >> > > > > > > > > > >> >> > >>> do more harm than good. > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >>> -Val > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >>> On Thu, Mar 25, 2021 at 12:23 PM Alexei > >> >> > > Scherbakov > >> >> > > > < > >> >> > > > > > > > > > >> >> > >>> alexey.scherbak...@gmail.com> wrote: > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >>>> I think both options are fine, but > >> >> personally > >> >> > > lean > >> >> > > > > > > toward > >> >> > > > > > > > > > >> >> > >>>> CompletableFuture. > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>>> чт, 25 мар. 2021 г. в 17:56, Atri > >> >> > > > > > > > > > >> >> > >>>> Sharma > >> < > >> >> > > > > > > a...@apache.org > >> >> > > > > > > > >: > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>>>> I would suggest using > >> >> > > > > > > > > > >> >> > >>>>> CompletableFuture > >> >> > > > > > > > > > >> >> > >>>>> -- > >> >> I > >> >> > > > don't > >> >> > > > > > see > >> >> > > > > > > a > >> >> > > > > > > > > need > >> >> > > > > > > > > > >> for > >> >> > > > > > > > > > >> >> > >>>>> a > >> >> > > > > > > > > > >> >> > >>>> custom > >> >> > > > > > > > > > >> >> > >>>>> interface that is unique to us. > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>>> It also allows a lower barrier for > new > >> >> > > > contributors > >> >> > > > > > for > >> >> > > > > > > > > > >> >> understanding > >> >> > > > > > > > > > >> >> > >>>>> existing code > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>>> On Thu, 25 Mar 2021, 20:18 Andrey > >> >> Mashenkov, > >> >> > < > >> >> > > > > > > > > > >> >> > >>> andrey.mashen...@gmail.com > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>>> wrote: > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>>>> Hi Igniters, > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> I'd like to start a discussion about > >> >> > replacing > >> >> > > > our > >> >> > > > > > > > custom > >> >> > > > > > > > > > >> >> > >>> IgniteFuture > >> >> > > > > > > > > > >> >> > >>>>>> class with CompletableFuture - > >> >> > > > > > > > > > >> >> > >>>>>> existed > >> >> > > > > > > > > > >> >> > >>>>>> JDK > >> >> > > class > >> >> > > > > > > > > > >> >> > >>>>>> or rework it's implementation (like > >> some > >> >> > other > >> >> > > > > > > products > >> >> > > > > > > > > > done) > >> >> > > > > > > > > > >> to > >> >> > > > > > > > > > >> >> > >>>>>> a > >> >> > > > > > > > > > >> >> > >>>>>> composition of CompletionStage and > >> >> > > > > > > > > > >> >> > >>>>>> Future > >> >> > > > > > interfaces. > >> >> > > > > > > > > > >> >> > >>>>>> or maybe other option if you have > any > >> >> ideas. > >> >> > > Do > >> >> > > > > you? > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> 1. The first approach pros and cons > >> >> > > > > > > > > > >> >> > >>>>>> are > >> >> > > > > > > > > > >> >> > >>>>>> + Well-known JDK class > >> >> > > > > > > > > > >> >> > >>>>>> + Already implemented > >> >> > > > > > > > > > >> >> > >>>>>> - It is a class, not an interface. > >> >> > > > > > > > > > >> >> > >>>>>> - Expose some potentially harmful > >> >> > > > > > > > > > >> >> > >>>>>> methods > >> >> > like > >> >> > > > > > > > > "complete()". > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> On the other side, it has copy() > >> >> > > > > > > > > > >> >> > >>>>>> method > >> >> > > > > > > > > > >> >> > >>>>>> to > >> >> > > > create > >> >> > > > > > > > > defensive > >> >> > > > > > > > > > >> copy > >> >> > > > > > > > > > >> >> > >> and > >> >> > > > > > > > > > >> >> > >>>>>> minimalCompletionStage() to restrict > >> >> harmful > >> >> > > > > method > >> >> > > > > > > > usage. > >> >> > > > > > > > > > >> >> > >>>>>> Thus, this look like an applicable > >> >> solution, > >> >> > > but > >> >> > > > > we > >> >> > > > > > > > should > >> >> > > > > > > > > > be > >> >> > > > > > > > > > >> >> > >> careful > >> >> > > > > > > > > > >> >> > >>>>>> exposing internal future to the > >> outside. > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> 2. The second approach is to > >> >> > > > > > > > > > >> >> > >>>>>> implement > >> >> > > > > > > > > > >> >> > >>>>>> our > >> >> > own > >> >> > > > > > > interface > >> >> > > > > > > > > > like > >> >> > > > > > > > > > >> >> > >>>>>> the > >> >> > > > > > > > > > >> >> > >>> next > >> >> > > > > > > > > > >> >> > >>>>> one: > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> interface IgniteFuture<T> extends > >> >> > > > > > CompletableStage<T>, > >> >> > > > > > > > > > >> Future<T> > >> >> > > > > > > > > > >> >> > >>>>>> { > >> >> > > > > > > > > > >> >> > >>>>>> } > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> Pros and cons are > >> >> > > > > > > > > > >> >> > >>>>>> + Our interfaces/classes contracts > >> >> > > > > > > > > > >> >> > >>>>>> will > >> >> > expose > >> >> > > > an > >> >> > > > > > > > > interface > >> >> > > > > > > > > > >> >> > >>>>>> rather > >> >> > > > > > > > > > >> >> > >>> than > >> >> > > > > > > > > > >> >> > >>>>>> concrete implementation. > >> >> > > > > > > > > > >> >> > >>>>>> + All methods are safe. > >> >> > > > > > > > > > >> >> > >>>>>> - Some implementation is required. > >> >> > > > > > > > > > >> >> > >>>>>> - CompletableStage has a method > >> >> > > > > > toCompletableFuture() > >> >> > > > > > > > and > >> >> > > > > > > > > > can > >> >> > > > > > > > > > >> be > >> >> > > > > > > > > > >> >> > >>>>> converted > >> >> > > > > > > > > > >> >> > >>>>>> to CompletableFuture. This should be > >> >> > > supported. > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> However, we still could wrap > >> >> > CompletableFuture > >> >> > > > and > >> >> > > > > > > don't > >> >> > > > > > > > > > >> >> > >>>>>> bother > >> >> > > > > > > > > > >> >> > >> about > >> >> > > > > > > > > > >> >> > >>>>>> creating a defensive copy. > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> Other project experience: > >> >> > > > > > > > > > >> >> > >>>>>> * Spotify uses CompletableFuture > >> >> > > > > > > > > > >> >> > >>>>>> directly > >> >> > [1]. > >> >> > > > > > > > > > >> >> > >>>>>> * Redis goes the second approach [2] > >> >> > > > > > > > > > >> >> > >>>>>> * Vertx explicitly extends > >> >> CompletableFuture > >> >> > > > [3]. > >> >> > > > > > > > However, > >> >> > > > > > > > > > >> >> > >>>>>> they > >> >> > > > > > > > > > >> >> > >> have > >> >> > > > > > > > > > >> >> > >>>>> custom > >> >> > > > > > > > > > >> >> > >>>>>> future classes and a number of > >> >> > > > > > > > > > >> >> > >>>>>> helpers > >> >> that > >> >> > > > could > >> >> > > > > be > >> >> > > > > > > > > > replaced > >> >> > > > > > > > > > >> >> > >>>>>> with > >> >> > > > > > > > > > >> >> > >>>>>> CompletableStage. Maybe it is just a > >> >> > legacy.' > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> Any thoughts? > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> [1] > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > > >> >> > > > > > > > > > >> >> > > > > > > > > >> >> > > > > > > > >> >> > > > > > > >> >> > > > > > >> >> > > > > >> >> > > > >> >> > > >> >> > >> > https://spotify.github.io/completable-futures/apidocs/com/spotify/futures/ConcurrencyReducer.html > >> >> > > > > > > > > > >> >> > >>>>>> [2] > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > > >> >> > > > > > > > > > >> >> > > > > > > > > >> >> > > > > > > > >> >> > > > > > > >> >> > > > > > >> >> > > > > >> >> > > > >> >> > > >> >> > >> > https://lettuce.io/lettuce-4/release/api/com/lambdaworks/redis/RedisFuture.html > >> >> > > > > > > > > > >> >> > >>>>>> [3] > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > > >> >> > > > > > > > > > >> >> > > > > > > > > >> >> > > > > > > > >> >> > > > > > > >> >> > > > > > >> >> > > > > >> >> > > > >> >> > > >> >> > >> > https://javadoc.io/static/org.jspare.vertx/vertx-jspare/1.1.0-M03/org/jspare/vertx/concurrent/VertxCompletableFuture.html > >> >> > > > > > > > > > >> >> > >>>>>> -- > >> >> > > > > > > > > > >> >> > >>>>>> Best regards, > >> >> > > > > > > > > > >> >> > >>>>>> Andrey V. Mashenkov > >> >> > > > > > > > > > >> >> > >>>>>> > >> >> > > > > > > > > > >> >> > >>>>> > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>>> -- > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>>> Best regards, > >> >> > > > > > > > > > >> >> > >>>> Alexei Scherbakov > >> >> > > > > > > > > > >> >> > >>>> > >> >> > > > > > > > > > >> >> > >>> > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > >> -- > >> >> > > > > > > > > > >> >> > >> Best regards, > >> >> > > > > > > > > > >> >> > >> Alexey > >> >> > > > > > > > > > >> >> > >> > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> >> -- > >> >> > > > > > > > > > >> >> Best regards, > >> >> > > > > > > > > > >> >> Andrey V. Mashenkov > >> >> > > > > > > > > > >> >> > >> >> > > > > > > > > > >> > > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > >> -- > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > >> Best regards, > >> >> > > > > > > > > > >> Ivan Pavlukhin > >> >> > > > > > > > > > >> > >> >> > > > > > > > > > > > >> >> > > > > > > > > > > >> >> > > > > > > > > > > >> >> > > > > > > > > > -- > >> >> > > > > > > > > > > >> >> > > > > > > > > > Best regards, > >> >> > > > > > > > > > Ivan Pavlukhin > >> >> > > > > > > > > > > >> >> > > > > > > > > > >> >> > > > > > > > > >> >> > > > > > > > > >> >> > > > > > > > -- > >> >> > > > > > > > Best regards, > >> >> > > > > > > > Andrey V. Mashenkov > >> >> > > > > > > > > >> >> > > > > > > > >> >> > > > > > -- > >> >> > > > > > Regards, > >> >> > > > > > > >> >> > > > > > Atri > >> >> > > > > > Apache Concerted > >> >> > > > > > > >> >> > > > > > >> >> > > > > >> >> > > > >> >> > > >> >> > >> >> > >> >> -- > >> >> Best regards, > >> >> Andrey V. Mashenkov > >> >> > >> > > >> > >> > >> -- > >> > >> Best regards, > >> Ivan Pavlukhin > >> > >> > > > > -- > > Best regards, > > Andrey V. Mashenkov > > > > > -- > > Best regards, > Ivan Pavlukhin > > -- Best regards, Andrey V. Mashenkov