CoreyKaylor / Lightning.NET

.NET library for LMDB key-value store
Other
397 stars 82 forks source link

.NET Core 3.1, .NET 5 Lightning.NET multi-targeting breaks `lmdb.dll` copying for multi-targeted projects #143

Closed Aaronontheweb closed 2 years ago

Aaronontheweb commented 3 years ago

This is most likely an MSBuild problem with the latest sources in master, but it will definitely affect users during the next NuGet release. I've been able to reproduce the issue here: https://github.com/akkadotnet/akka.net/pull/5180

We have a test project that multi-targets and consumes Lightning.NET:

When targeting the most recent version of Lightning.NET (0.13.0) on NuGet we're able to run all of our tests that depend on LMDB in this project without any issues. In the output directory for each of those builds we can see the lmdb.dll successfully copied right next to the LightningDB.dll:

image

LightningDB 0.13.0 only targets .NET Standard 2.0 and doesn't multi-target - this appears to be one of the reasons why everything works with v0.13.0.

However, if I build and publish a package from the latest sources in master, which now targets:

All three of my builds are missing lmdb.dll from the output directory:

image

And all three of them fail with the following runtime error during execution (on Windows primarily):

Node #2(second)][INFO][8/7/2021 3:48:53 AM][Thread 0028][akka.tcp://DDataClusterShardingRememberEntitiesSpec@localhost:50592/system/sharding/replicator/durableStore] Using durable data in LMDB directory [D:\a\1\s\src\contrib\cluster\Akka.Cluster.Sharding.Tests.MultiNode\bin\Release\net471\target\ClusterShardingMinMembersSpec\sharding-ddata-DDataClusterShardingRememberEntitiesSpec-replicator-50592]
[Node #2(second)]   at LightningDB.Native.Lmdb.mdb_env_create(IntPtr& env)
[Node #2(second)]   at LightningDB.LightningEnvironment..ctor(String path, EnvironmentConfiguration configuration)
[Node #2(second)]   at Akka.DistributedData.LightningDB.LmdbDurableStore.GetLightningEnvironment()
[Node #2(second)]   at Akka.DistributedData.LightningDB.LmdbDurableStore.<Active>b__17_0(Store store)
[Node #2(second)]   at lambda_method(Closure , Object , Action`1 , Action`1 )
[Node #2(second)]   at Akka.Actor.ReceiveActor.ExecutePartialMessageHandler(Object message, PartialAction`1 partialAction)
[Node #2(second)]   at Akka.Actor.ActorCell.<>c__DisplayClass114_0.<Akka.Actor.IUntypedActorContext.Become>b__0(Object m)
[Node #2(second)]   at Akka.Actor.ActorBase.AroundReceive(Receive receive, Object message)
[Node #2(second)]   at Akka.Actor.ActorCell.ReceiveMessage(Object message)
[Node #2(second)]   at Akka.Actor.ActorCell.Invoke(Envelope envelope)
[Node #2(second)]Cause: System.DllNotFoundException: Unable to load DLL 'lmdb': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
[Node #2(second)]   at LightningDB.Native.Lmdb.mdb_env_create(IntPtr& env)
[Node #2(second)]   at LightningDB.LightningEnvironment..ctor(String path, EnvironmentConfiguration configuration)
[Node #2(second)]   at Akka.DistributedData.LightningDB.LmdbDurableStore.GetLightningEnvironment()
[Node #2(second)]   at Akka.DistributedData.LightningDB.LmdbDurableStore.<Active>b__17_0(Store store)
[Node #2(second)]   at lambda_method(Closure , Object , Action`1 , Action`1 )
[Node #2(second)]   at Akka.Actor.ReceiveActor.ExecutePartialMessageHandler(Object message, PartialAction`1 partialAction)
[Node #2(second)]   at Akka.Actor.ActorCell.<>c__DisplayClass114_0.<Akka.Actor.IUntypedActorContext.Become>b__0(Object m)
[Node #2(second)]   at Akka.Actor.ActorBase.AroundReceive(Receive receive, Object message)
[Node #2(second)]   at Akka.Actor.ActorCell.ReceiveMessage(Object message)
[Node #2(second)]   at Akka.Actor.ActorCell.Invoke(Envelope envelope)

I don't necessarily think the issue is the presence of lmdb.dll being in the exact same folder as LightningDB.dll - but this is one of the few things that definitively changed between versions of the package. I think this is an effect of the package moving to multi-targeting and how those dependencies now get resolved by downstream consumers who multi-target.

N.B. I have another project that only targets .NET Core 3.1 using this same package. It doesn't have lmdb.dll in its output directory either but it runs just fine, able to resolve the native .DLL from its runtimes/{platform} folder. This tells me that this issue is a combination of both the Lightning.NET and the downstream consumer both multi-targeting.

I suspect that in order to fix this issue we'll need to handle some additional edge cases here:

https://github.com/CoreyKaylor/Lightning.NET/blob/2a8791ba9e39fab39353bf6c39896249eebf6452/src/LightningDB/LightningDB.targets#L3-L29

I'm going to take a look at how SQLite addresses this and see if I can submit a PR myself. But I wanted to fully document the issue for the sake of staying organized and in case anyone else has any ideas on how to address this.

Aaronontheweb commented 3 years ago

Also, I'm taking a look at some of the suggestions on this thread to help debug in more detail what's actually going on here: https://github.com/dotnet/runtime/issues/13472

AlgorithmsAreCool commented 3 years ago

Hey thanks for the report. I'll try to crave some time this week to close out some of these issues.

Aaronontheweb commented 3 years ago

No problem! I worked around the issue here https://github.com/akkadotnet/akka.net/pull/5180 - by just manually copying the binaries and the Lightning.targets file into our two testing projects which were affected.

As far as I can tell this issue doesn't affect normal usage of the plugin in applications - just multi-targeted tests.

CoreyKaylor commented 2 years ago

I'm speculating that in the setup it's possible that the LightningDBTargetRuntimeRelativePath might be off. If so, you should be able to set this to the correct relative path for your test projects. You can see I had to do the same in the test project here. I'm going to publish 0.14.0 shortly. The only change to the targets file was the additional file inclusion for the auto grow binary on Windows. Otherwise the changes are the same as before. Let me know if the issue continues to be "worse than before" now that it's multi-targeting in the new version.

CoreyKaylor commented 2 years ago

https://github.com/CoreyKaylor/Lightning.NET/releases/tag/v0.14.0 is published to nuget.org now.

CoreyKaylor commented 2 years ago

Feel free to re-open if there is still an issue that isn't fixed with my previous comment.