Rx Observable Window with closing function with parameter - system.reactive

I'm trying to separate observable into windows (or for my purposes also Buffers are fine) while being able to close windows/buffers at custom location.
E.g. I have an observable which produces integers starting at 1 and moving up. I want to close a window at each number which is divisible by 7. My closing function would need to take in the item as parameter in that case.
There is an overload of Window method:
Window<TSource, TWindowClosing>(IObservable<TSource>, Func<IObservable<TWindowClosing>>)
Either it cant be done using this overload, or I can't wrap my head around it. Documentation describes that it does exactly what I want but does not show an example. Also, it shows an example of non-deterministic closing, which depends on timing when closing observable collection emits items.
The Window operator breaks up an observable sequence into consecutive
non-overlapping windows. The end of the current window and start of
the next window is controlled by an observable sequence which is the
result of the windowClosingSelect function which is passed as an input
parameter to the operator. The operator could be used to group a set
of events into a window. For example, states of a transaction could be
the main sequence being observed. Those states could include:
Preparing, Prepared, Active, and Committed/Aborted. The main sequence
could include all of those states are they occur in that order. The
windowClosingSelect function could return an observable sequence that
only produces a value on the Committed or Abort states. This would
close the window that represented transaction events for a particular
transaction.
I'm thinking something like following would do the job, but I'd have to implement it myself:
Window<TSource, TWindowClosing>(IObservable<TSource>, Func<TSource, bool>)
Is such windowing possible with built-in functions (I know I can build one myself)?
Is it possible to close a window based on emitted item or only non-deterministically, once an item is emitted from windowing observable?

Use the original sequence with a Where clause as your closing sequence. If your source sequence is cold, then make use of Publish and RefCount to make it work correctly.
var source = ...;
var sharedSource = source.Publish().RefCount();
var closingSignal = sharedSource.Where(i => (i % 7) == 0);
var windows = sharedSource.Window(() => closingSignal);

Related

Thread safe operations on XDP

I was able to confirm from the documentation that bpf_map_update_elem is an atomic operation if done on HASH_MAPs. Source (https://man7.org/linux/man-pages/man2/bpf.2.html). [Cite: map_update_elem() replaces existing elements atomically]
My question is 2 folds.
What if the element does not exist, is the map_update_elem still atomic?
Is the XDP operation bpf_map_delete_elem thread safe from User space program?
The map is a HASH_MAP.
Atomic ops, race conditions and thread safety are sort of complex in eBPF, so I will make a broad answer since it is hard to judge from your question what your goals are.
Yes, both the bpf_map_update_elem command via the syscall and the helper function update the maps 'atmomically', which in this case means that if we go from value 'A' to value 'B' that the program always sees either 'A' or 'B' not some combination of the two(first bytes of 'B' and last bytes of 'A' for example). This is true for all map types. This holds true for all map modifying syscall commands(including bpf_map_delete_elem).
This however doesn't make race conditions impossible since the value of the map may have changed between a map_lookup_elem and the moment you update it.
What is also good to keep in mind is that the map_lookup_elem syscall command(userspace) works differently from the helper function(kernelspace). The syscall will always return a copy of the data which isn't mutable. But the helper function will return a pointer to the location in kernel memory where the map value is stored, and you can directly update the map value this way without using the map_update_elem helper. That is why you often see hash maps used like:
value = bpf_map_lookup_elem(&hash_map, &key);
if (value) {
__sync_fetch_and_add(&value->packets, 1);
__sync_fetch_and_add(&value->bytes, skb->len);
} else {
struct pair val = {1, skb->len};
bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
}
Note that in this example, __sync_fetch_and_add is used to update parts of the map value. We need to do this since updating it like value->packets++; or value->packets += 1 would result in a race condition. The __sync_fetch_and_add emits a atomic CPU instruction which in this case fetches, adds and writes back all in one instruction.
Also, in this example, the two struct fields are atomically updated, but not together, it is still possible for the packets to have incremented but bytes not yet. If you want to avoid this you need to use a spinlock(using the bpf_spin_lock and bpf_spin_unlock helpers).
Another way to sidestep the issue entirely is to use the _PER_CPU variants of maps, where you trade-off congestion/speed and memory use.

What is the order that reactive statements are executed in?

Let's say we have the following component script
let x = 0;
function increase() {
x += 1;
}
$: console.log(x)
$: if (x == 4) {
x = 0;
}
https://svelte.dev/repl/2bca979673114afea9fc6b37434653a3?version=3.29.0
Intuitively I would expect from cotinually calling increase, is to have the values 0,1,2,3,4,1,2,3,4,... logged to the console. But this is not the case. Instead, the second reactive statement runs first, and 4 is never logged; it is 0. Switching the order of the reactive statements has no effect.
How do you make the logging statement execute before the other one and what is the reason that it runs second, in the first place?
The order in which reactive statements that depends on the same variables are run is not specified / guaranteed by Svelte. You have to build your components with the expectation that they can be run in any order, and make sure that your code doesn't depend on any specific order.
You must not rely on a given order you observe in a specific case either -- it can change following a change in Svelte's internal implementation (e.g. new optimisations), or when the code of your own component changes (causing a different compiler output, that can change the order of reactive blocks for hard-to-anticipate reasons).
The reasons why this happens are highly technical (i.e. I don't really know), but they boil down to ease of implementation / optimization of the compiler. Reactive statements are a kind of async operations, that typically can't guarantee order of execution.
If you really need 2 operations to happen in a specific order then, for peace of mind, you need them in the same reactive block.
$: {
console.log(x) // op 1
if (x == 4) x = 0 // op 2
}

Confused about Observable vs. Single in functions like readCharacteristic()

In the RxJava2 version of RxAndroidBle, the functions readCharacteristic() and writeCharacteristic() return Single<byte[]>.
The example code to read a characteristic is:
device.establishConnection(false).flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(characteristicUUID))
But the documentation for flatMap() says the mapping function is supposed to return an ObservableSource. Here, it returns a Single. How can this work?
Update: I looked at possibilities using operators like .single() and .singleOrError() but they all seem to require that the upstream emits one item and then completes. But establishConnection() doesn't ever complete. (This is one reason I suggested that perhaps establishConnection() should be reimagined as a Maybe, and some other way be provided to disconnect rather than just unsubscribing.)
You're totally correct, this example cannot be compiled. it's probably leftover from RxJava1 version, where Single wasn't exists.
Simple fix with the same result is to use RxJava2 flatMapSingle for instance:
device.establishConnection(false)
.flatMapSingle(rxBleConnection -> rxBleConnection.readCharacteristic(characteristicUUID))
flatMapSingle accepts a Single as the return value, and will map the success value of the input Single to an emission from the upstream Observable.
The point is, that RxJava has more specific Observable types, that exposes the possible series of emission expected from this Observable. Some methods now return Single as this is the logical operation of their stream (readCharacteristic()), some Observable as they will emit more than single emission (establishConnection() - connection status that can be changed over time).
But RxJava2 also provided many operators to convert between the different types and it really depends on your needs and scenario.
Thanks Rob!
In fact, the README was deprecated and required some pimping here and there. Please have a look if it's ok now.
I think I found the answer I was looking for. The crucial point:
Single.fromObservable(observableSource) doesn't do anything until it receives the second item from observableSource! Assuming that the first item it receives is a valid emission, then if the second item is:
onComplete(), it passes the first item to onSuccess();
onNext(), it signals IndexOutOfBoundsException since a Single can't emit more than one item;
onError(), it presumably forwards the error downstream.
Now, device.establishConnection() is a 1-item, non-completing Observable. The RxBleConnecton it emits is flatMapped to a Single with readCharacteristic(). But (another gotcha), flatMapSingle subscribes to these Singles and combines them into an Observable, which doesn't complete until the source establishConnection() does. But the source doesn't ever complete! Therefore the Single we're trying to create won't emit anything, since it doesn't receive that necessary second item.
The solution is to force the generation of onComplete() after the first (and only) item, which can be done with take(1). This will satisfy the Single we're creating, and cause it to emit the Characteristic value we're interested in. Hope that's clear.
The code:
Single<byte[]> readCharacteristicSingle( RxBleDevice device, UUID characteristicUUID ) {
return Single.fromObservable(
device.establishConnection( false )
.flatMapSingle( connection -> connection.readCharacteristic( characteristicUUID ) )
.take( 1L ) // make flatMapSingle's output Observable complete after the first emission
// (this makes the Single call onSuccess())
);
}

Concat stream at the arbitrary position

Yet another question about RxJava. Im on fire this week.
I have the following problem to solve with RxJava:
I have a stream of Model objects which I transform into stream of ViewModel objects. Everything is pretty straight forward - I just use map operator and it works fine. However I have one requirement - sometimes I need to add fake ViewModel after the element which satisfy given criteria. I.e:
models: ---1----2----3----4----5----6----->
vvvvvvvvvvvvvvvvv
viewmodels: --A(1)-A(2)-A(3)-A(4)-A(5)-A(6)--->
Now let's say I want to add fake viewmodel after the last odd number in the viewmodels stream:
result: --A(1)-A(2)-A(3)-A(4)-A(5)-A(-1)-A(6)--->
I looked at concatMap operator - it allows me to extend given stream with more elements, but Im not sure how do I add the logic of adding new elements at the arbitrary position.
EDIT: Position for adding fake model is not known. "last odd number" case was chosen just as a example. In real situation I have more complex logic of deciding where fake model goes. There is a chance fake model should not be added at all if item which satisfies given criteria is not found in the stream
EDIT2: To get more real, both my Model and ViewModel classes have boolean flag inside. Let's call this flag isFinished. In my case I need to add fake viewmodel after the last "finished" item in the stream. If none of them is finished - no fake viewmodel should be added. So ultimately I have maximum one fake model added
In your example the decision to insert a fake ViewModel depends on knowing when the stream has completed. The last odd number is an easy case to deal with using buffer to look ahead a little. When the end of the stream is close the buffer will not be of size 3 and you can check the index to see if you are at an odd position. This should give you the general idea and I leave it to you to think of the edge cases properly:
modelsWithIndex
.buffer(3,1)
.concatMap(list -> {
if (list.size()==3 || list.get(0).index % 2 == 0)
return Observable.just(list.get(0).model);
else
return Observable.just(list.get(0).model, createFakeModel());
});
After Edit2 it seems that the distance to the end of the stream can be arbitrarily large so buffer is not the way to go. For this case I would use Transfomers.toListWhile() from rxjava-extras. The condition function to pass as a parameter would return false once model.finished returns true then you could use the .buffer(2,1).flatMap() trick to detect the last list and return Observable.just(fakeModel).concatWith(Observable.from(list)) or if not the last just return Observable.from(list).

How to buffer based on time and count, but stopping the timer if no events occur

I'm producing a sequence of 50 items each tree seconds. I then want to batch them at max 20 items, but also not waiting more than one second before I release the buffer.
That works great!
But since the interval never dies, Buffer keeps firing empty batch chunks...
How can I avoid that? Shure Where(buf => buf.Count > 0)should help - but that seems like a hack.
Observable
.Interval(TimeSpan.FromSeconds(3))
.Select(n => Observable.Repeat(n, 50))
.Merge()
.Buffer(TimeSpan.FromSeconds(1), 20)
.Subscribe(e => Console.WriteLine(e.Count));
Output:
0-0-0-20-20-10-0-20-20-10-0-0-20-20
The Where filter you propose is a sound approach, I'd go with that.
You could wrap the Buffer and Where into a single helper method named to make the intent clearer perhaps, but rest assured the Where clause is idiomatic Rx in this scenario.
Think of it this way; an empty Buffer is relaying information that no events occurred in the last second. While you can argue that this is implicit, it would require extra work to detect this if Buffer didn't emit an empty list. It just so happens it's not information you are interested in - so Where is an appropriate way to filter this information out.
A lazy timer solution
Following from your comment ("...the timer... be[ing] lazily initiated...") you can do this to create a lazy timer and omit the zero counts:
var source = Observable.Interval(TimeSpan.FromSeconds(3))
.Select(n => Observable.Repeat(n, 50))
.Merge();
var xs = source.Publish(pub =>
pub.Buffer(() => pub.Take(1).Delay(TimeSpan.FromSeconds(1))
.Merge(pub.Skip(19)).Take(1)));
xs.Subscribe(x => Console.WriteLine(x.Count));
Explanation
Publishing
This query requires subscribing to the source events multiple times. To avoid unexpected side-effects, we use Publish to give us pub which is a stream that multicasts the source creating just a single subscription to it. This replaces the older Publish().RefCount() technique that achieved the same end, effectively giving us a "hot" version of the source stream.
In this case, this is necessary to ensure the subsequent buffer closing streams produced after the first will start with the current events - if the source was cold they would start over each time. I wrote a bit about publishing here.
The main query
We use an overload of Buffer that accepts a factory function that is called for every buffer emitted to obtain an observable stream whose first event is a signal to terminate the current buffer.
In this case, we want to terminate the buffer when either the first event into the buffer has been there for a full second, or when 20 events have appeared from the source - whichever comes first.
To achieve this we Merge streams that describe each case - the Take(1).Delay(...) combo describes the first condition, and the Skip(19).Take(1) describes the second.
However, I would still test performance the easy way, because I still suspect this is overkill, but a lot depends on the precise details of the platform and scenario etc.
After using the accepted answer for quite a while I would now suggest a different implementation (inspired by James Skip / Take approach and this answer):
var source = Observable.Interval(TimeSpan.FromSeconds(3))
.Select(n => Observable.Repeat(n, 50))
.Merge();
var xs = source.BufferOmitEmpty(TimeSpan.FromSeconds(1), 20);
xs.Subscribe(x => Console.WriteLine(x.Count));
With an extension method BufferOmitEmpty like:
public static IObservable<IList<TSource>> BufferOmitEmpty<TSource>(this IObservable<TSource> observable, TimeSpan maxDelay, int maxBufferCount)
{
return observable
.GroupByUntil(x => 1, g => Observable.Timer(maxDelay).Merge(g.Skip(maxBufferCount - 1).Take(1).Select(x => 1L)))
.Select(x => x.ToArray())
.Switch();
}
It is 'lazy', because no groups are created as long as there are no elements on the source sequence, so there are no empty buffers. As in Toms answer there is an other nice advantage to the Buffer / Where implementation, that is the buffer is started when the first element arrives. So elements following each other within buffer time after a quiet period are processed in the same buffer.
Why not to use the Buffer method
Three problems occured when I was using the Buffer approach (they might be irrelevant for the scope of the question, so this is a warning to people who use stack overflow answers in different contexts like me):
Because of the Delay one thread is used per subscriber.
In scenarios with long running subscribers elements from the source sequence can be lost.
With multiple subscribers it sometimes creates buffers with count greater than maxBufferCount.
(I can supply sample code for 2. and 3. but I'm insecure whether to post it here or in a different question because I cannot fully explain why it behaves this way)
RxJs5 has hidden features buried into their source code. It turns out it's pretty easy to achieve with bufferTime
From the source code, the signature looks like this:
export function bufferTime<T>(this: Observable<T>, bufferTimeSpan: number, bufferCreationInterval: number, maxBufferSize: number, scheduler?: IScheduler): Observable<T[]>;
So your code would be like this:
observable.bufferTime(1000, null, 20)