skip to content
Relatively General .NET

ExternalFinalizer: Adding a finalizer to 3rd party objects

by Oren Eini

posted on: March 13, 2023

Let’s say that you have the following scenario, you have an object in your hands that is similar to this one: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters public class Frame : IDisposable { private void* _data; private int _len; public Frame(int size) { _len = size; _data = NativeCalls.AllocateFrame(size) ?? throw new OutOfMemoryException(); } public void Dispose() { NativeCalls.FreeFrame(_data,_len); } } view raw Item.cs hosted with ❤ by GitHub It holds some unmanaged resources, so you have to dispose it. However, this is used in the following manner: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters public Frame CurrentFrame => _frame; public void UpdateFrame(Frame f) { var old = _frame; _frame = f; old.Dispose(); } view raw Usage.cs hosted with ❤ by GitHub What is the problem? This object may be used concurrently. In the past, the frame was never updated, so it was safe to read from it from multiple threads. Now there is a need to update the frame, but that is a problem. Even though only a single thread can update the frame, there may be other threads that hold a reference to it. That is a huge risk, since they’ll access freed memory. At best, we’ll have a crash, more likely it will be a security issue. At this point in time, we cannot modify all the calling sites without incurring a huge cost. The Frame class is coming from a third party and cannot be changed, so what can we do? Not disposing the frame would lead to a memory leak, after all. Here is a nice trick to add a finalizer to a third party class. Here is how the code works: This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters Show hidden characters public ConditionalWeakTable<Frame,FrameDisposer> _linkInstances = new(); public class FrameDisposer { public Frame Frame; ~FrameDisposer() { Frame.Dispose(); } } public void UpdateFrame(Frame f) { var old = _frame; _linkInstances.Add(old, new FrameDisposer{ Frame = old } ); _frame = f; } view raw ExternalFinalizer.cs hosted with ❤ by GitHub The ConditionalWeakTable associates the lifetime of the disposer with the frame, so only where there are no more outstanding references to the frame (guaranteed by the GC), the finalizer will be called and the memory will be freed. It’s not the best option, but it is a great one if you want to make minimal modifications to the code and get the right behavior out of it.

Measuring performance of Roslyn Source Generators

by Gérald Barré

posted on: March 13, 2023

A Roslyn source generator is a tool that allows you to programmatically generate C# or VB.NET source code at compile time. Source generators are implemented as Roslyn analyzers, which are NuGet packages that contain one or more source generators. When you include a source generator NuGet package in

Next week: Kobo's Journey Into High Performance and Reliable Document Databases at InfoQ

by Oren Eini

posted on: March 10, 2023

Trevor Hunter from Kobo Rakuten is going to be speaking about Kobo’s usage of RavenDB in a webinar next Wednesday. When I started at Kobo, we needed to look beyond the relational and into document databases. Our initial technology choice didn't work out for us in terms of reliability, performance, or flexibility, so we looked for something new and set on a journey of discovery, exploratory testing, and having fun pushing contender technologies to their limits (and breaking them!). In this talk, you'll hear about our challenges, how we evaluated the options, and our experience since widely adopting RavenDB. You'll learn about how we use it, areas we're still a bit wary of, and features we're eager to make more use of. I'll also dive into the key aspects of development - from how it affects our unit testing to the need for a "modern DBA" role on a development team. About the speaker: Trevor Hunter: "I am a leader and coach with a knack for technology. I’m a Chief Technology Officer, a mountain biker, a husband, and a Dad. My curiosity to understand how things work and my desire to use that understanding to help others are the things I hope my kids inherit from me. I am currently the Chief Technology Officer of Rakuten Kobo. Here I lead the Research & Development organization where our mission is to deliver the best devices and the best services for our readers. We innovate, create partnerships, and deliver software, hardware, and services to millions of users worldwide." You can register to the webinar here.

2022 Year in Review

by Ardalis

posted on: March 10, 2023

This is something I usually try to write in early January but here it is March already and I'm finally feeling up to it. It's been a rough…Keep Reading →

Testing Roslyn Incremental Source Generators

by Gérald Barré

posted on: March 06, 2023

Roslyn Source Generators allow generating code based on the current project code and additional files. Each keystroke in the editor may trigger source generators. So, it is important to ensure that the source generators are fast enough to not impact the user experience. One important feature is inc

RavenDB Sharding Progress

by Oren Eini

posted on: March 02, 2023

RavenDB Sharding is now running as a production replication in our backend systems and we are stepping up our testing in a real-world environment. We are now also publishing nightly builds of RavenDB 6.0, including Sharding support. There are some known (minor) issues in the Studio, which we are busy fixing, but it is already possible to create and manage sharded clusters. As usual, we would love your feedback. Here are some of the new features that I’m excited about, you can see that we have an obese bucket here, far larger than all other items: And we can drill down and find why: We have quite a few revisions of a pretty big document, and they are all obviously under a single bucket. You can now also get query timings information across the entire sharded cluster, like so: And as you can see, this will give you a detailed view of exactly where the costs are. You can get the nightly build and start testing it right now. We would love to hear from you, especially as you test the newest features.

Backend API design principles: Don’t mirror your data

by Oren Eini

posted on: February 27, 2023

It’s very common to model your backend API as a set of endpoints that mirror your internal data model. For example, consider a blog engine, which may have: GET /users/{id}: retrieves information about a specific user, where {id} is the ID of the user GET /users/{id}/posts: retrieves a list of all posts made by a specific user, where {id} is the ID of the user POST /users/{id}/posts: creates a new post for a specific user, where {id} is the ID of the user GET /posts/{id}/comments: retrieves a list of all comments for a specific post, where {id} is the ID of the post POST /posts/{id}/comments: creates a new comment for a specific post, where {id} is the ID of the post This mirrors the internal structure pretty closely, and it is very likely that you’ll get to an API similar to this if you’ll start writing a blog backend. This represents the usual set of operations very clearly and easily. The problem is that the blog example is so attractive because it is inherently limited. There isn’t really that much going on in a blog from a data modeling perspective. Let’s consider a restaurant and how its API would look like: GET /menu: Retrieves the restaurant's menu POST /orders: Creates a new order POST /orders/{order_id}/items: Adds items to an existing order POST /payments: Allows the customer to pay their bill using a credit card This looks okay, right? We sit at a table, grab the menu and start ordering. From REST perspective, we need to take into account that multiple users may add items to the same order concurrently. That matters, because we may have bundles to take into account. John ordered the salad & juice and Jane the omelet, and Derek just got coffee. But coffee is already included in Jane’s order, so no separate charge for that. Here is what this will look like: ┌────┐┌────┐┌─────┐┌──────────────────────┐ │John││Jane││Derek││POST /orders/234/items│ └─┬──┘└─┬──┘└──┬──┘└─────┬────────────────┘ │ │ │ │ │ Salad & Juice │ │─────────────────────>│ │ │ │ │ │ │ Omelet │ │ │───────────────>│ │ │ │ │ │ │ │ Coffee │ │ │ │────────>│ The actual record we have in the end, on the other hand, looks like: Salad & Juice Omelet & Coffee In this case, we want the concurrent nature of separate requests, since each user will be ordering at the same time, but the end result should be the final tally, not just an aggregation of the separate totals. In the same sense, how would we handle payments? Can we do that in the same manner? ┌────┐┌────┐┌─────┐┌──────────────────┐ │John││Jane││Derek││POST /payments/234│ └─┬──┘└─┬──┘└──┬──┘└────────┬─────────┘ │ │ │ │ │ │ $10 │ │────────────────────────>│ │ │ │ │ │ │ │ $10 │ │ │──────────────────>│ │ │ │ │ │ │ │ $10 │ │ │ │───────────>│ In this case, however, we are in a very different state. What happens in this scenario if one of those charges were declined? What happens if they put too much. What happens if there is a concurrent request to add an item to the order while the payment is underway? When you have separate operations, you have to somehow manage all of that. Maybe a distributed transaction coordinator or by trusting the operator or by dumb luck, for a while. But this is actually an incredibly complex topic. And a lot of that isn’t inherent to the problem itself, but instead about how we modeled the interaction with the server. Here is the life cycle of an order: POST /orders: Creates a new order – returns the new order id ** POST /orders/{order_id}/items: Adds / removes items to an existing order ** POST /orders/{order_id}/submit: Submits all pending order items to the kitchen POST /orders/{order_id}/bill: Close the order, compute the total charge POST /payments/{order_id}: Handle the actual payment (or payments) I have marked with ** the two endpoints that may be called multiple times. Everything else can only be called once. Consider the transactional behavior around this sort of interaction. Adding / removing items from the order can be done concurrently. But submitting the pending orders to the kitchen is a boundary, a concurrent item addition would either be included (if it happened before the submission) or not (and then it will just be added to the pending items). We are also not going to make any determination on the offers / options that were selected by the diners until they actually move to the payment portion. Even the payment itself is handled via two interactions. First, we ask to get the bill for the order. This is the point when we’ll compute orders, and figure out what bundles, discounts, etc we have. The result of that call is the final tally. Second, we have the call to actually handle the payment. Note that this is one call, and the idea is that the content of this is going to be something like the following: { "order_id": "789", "total": 30.0, "payments": [ { "amount": 15.0, "payment_method": "credit_card", "card_number": "****-****-****-3456", "expiration_date": "12/22", "cvv": "123" }, { "amount": 10.0, "payment_method": "cash" }, { "amount": 5.0, "payment_method": "credit_card", "card_number": "****-****-****-5678", "expiration_date": "12/23", "cvv": "456" } ] } The idea is that by submitting it all at once, we are removing a lot of complexity from the backend. We don’t need to worry about complex interactions, race conditions, etc. We can deal with just the issue of handling the payment, which is complicated enough on its own, no need to borrow trouble. Consider the case that the second credit card fails the charge. What do we do then? We already charged the previous one, and we don’t want to issue a refund, naturally. The result here is a partial error, meaning that there will be a secondary submission to handle the remainder payment. From an architectural perspective, it makes the system a lot simpler to deal with, since you have well-defined scopes. I probably made it more complex than I should have, to be honest. We can simply make the entire process serial and forbid actual concurrency throughout the process. If we are dealing with humans, that is easy enough, since the latencies involved are short enough that they won’t be noticed. But I wanted to add the bit about making a part of the process fully concurrent, to deal with the more complex scenarios. In truth, we haven’t done a big change in the system, we simply restructured the set of calls and the way you interact with the backend. But the end result of that is the amount of code and complexity that you have to juggle for your infrastructure needs are far more lightweight. On real-world systems, that also has the impact of reducing your latencies, because you are aggregating multiple operations and submitting them as a single shot. The backend will also make things easier, because you don’t need complex transaction coordination or distributed locking. It is a simple change, on its face, but it has profound implications.

Extending the System Menu to add advanced commands in .NET

by Gérald Barré

posted on: February 27, 2023

Table Of ContentsWhat's the system menu?WinFormsWPF#What's the system menu?The system menu is the menu that appears when you right-click on the title bar of a window or when you press Alt+Space. It contains commands like 'Close', 'Move', 'Size', 'Minimize', 'Maximize', 'Restore', 'Help', etc. This