• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Giorgi / DuckDB.NET / 22921736195

10 Mar 2026 07:24PM UTC coverage: 89.526% (+0.08%) from 89.45%
22921736195

push

github

Giorgi
Update global.json

1255 of 1463 branches covered (85.78%)

Branch coverage included in aggregate %.

2651 of 2900 relevant lines covered (91.41%)

447643.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.87
/DuckDB.NET.Data/Connection/ConnectionManager.cs
1
using System.Collections.Concurrent;
2
using System.Threading;
3

4
namespace DuckDB.NET.Data.Connection;
5

6
/// <summary>
7
/// Creates, caches, and disconnects ConnectionReferences.
8
/// </summary>
9
internal class ConnectionManager
10
{
11
    public static readonly ConnectionManager Default = new();
3✔
12

13
    private static readonly ConcurrentDictionary<string, FileReference> ConnectionCache = new(StringComparer.OrdinalIgnoreCase);
3✔
14

15
    internal ConnectionReference GetConnectionReference(DuckDBConnectionString connectionString)
16
    {
17
        var filename = connectionString.DataSource;
64,944✔
18

19
        var fileRef = connectionString.InMemory && !connectionString.Shared ? new FileReference("") : null;
64,944✔
20

21
        //need to loop until we have a locked fileRef
22
        //that is also in the cache
23
        while (fileRef == null)
65,220✔
24
        {
25
            fileRef = ConnectionCache.GetOrAdd(filename, fn =>
64,995✔
26
            {
64,995✔
27
                fileRef = new FileReference(filename);
37,693✔
28
                return fileRef;
37,693✔
29
            });
64,995✔
30

31
            Monitor.Enter(fileRef);
64,995✔
32

33
            //Need to make sure what we have locked is still in the cache
34
            var existingFileRef = ConnectionCache.GetOrAdd(filename, fileRef);
64,995✔
35

36
            if (existingFileRef == fileRef)
64,995✔
37
            {
38
                //file in the cache matches what is locked, we are good!
39
                break;
40
            }
41

42
            //exit lock and try the whole thing again
43
            Monitor.Exit(fileRef);
276✔
44
            fileRef = null;
276✔
45
        }
46

47
        //now connect what needs to be connected
48
        try
49
        {
50
            if (fileRef.Database == null)
64,944✔
51
            {
52
                var path = connectionString.InMemory ? null : filename;
45,800✔
53

54
                NativeMethods.Configuration.DuckDBCreateConfig(out var config);
45,800✔
55
                using (config)
45,800✔
56
                {
57
                    foreach (var (option, value) in connectionString.Configuration)
183,272✔
58
                    {
59
                        var state = NativeMethods.Configuration.DuckDBSetConfig(config, option, value);
45,839✔
60

61
                        if (!state.IsSuccess())
45,839✔
62
                        {
63
                            throw new DuckDBException($"Error setting '{option}' to '{value}'");
6✔
64
                        }
65
                    }
66

67
                    var resultOpen = NativeMethods.Startup.DuckDBOpen(path, out var db, config, out var error);
45,794✔
68

69
                    if (!resultOpen.IsSuccess())
45,794!
70
                    {
71
                        throw new DuckDBException($"DuckDBOpen failed: {error}");
×
72
                    }
73
                    fileRef.Database = db;
45,794✔
74
                }
45,794✔
75
            }
76

77
            var resultConnect = NativeMethods.Startup.DuckDBConnect(fileRef.Database, out var nativeConnection);
64,938✔
78

79
            if (resultConnect.IsSuccess())
64,938!
80
            {
81
                fileRef.Increment();
64,938✔
82
            }
83
            else
84
            {
85
                throw new DuckDBException("DuckDBConnect failed");
×
86
            }
87

88
            return new ConnectionReference(fileRef, nativeConnection);
64,938✔
89
        }
90
        finally
91
        {
92
            if (Monitor.IsEntered(fileRef))
64,944✔
93
            {
94
                Monitor.Exit(fileRef);
64,719✔
95
            }
96
        }
64,944✔
97
    }
64,938✔
98

99
    internal void ReturnConnectionReference(ConnectionReference connectionReference)
100
    {
101
        var fileRef = connectionReference.FileReferenceCounter;
64,935✔
102

103
        lock (fileRef)
64,935✔
104
        {
105
            var nativeConnection = connectionReference.NativeConnection;
64,935✔
106

107
            nativeConnection.Dispose();
64,935✔
108

109
            var current = fileRef.Decrement();
64,935✔
110

111
            if (current < 0)
64,935!
112
            {
113
                throw new InvalidOperationException($"{fileRef.FileName} has been returned too many times");
×
114
            }
115

116
            if (current == 0)
64,935✔
117
            {
118
                fileRef.Database?.Dispose();
45,788!
119
                fileRef.Database = null;
45,788✔
120

121
                if (!string.IsNullOrEmpty(fileRef.FileName) && !ConnectionCache.TryRemove(fileRef.FileName, out _))
45,788!
122
                {
123
                    throw new InvalidOperationException($"Internal Error: tried to remove {fileRef.FileName} from cache but it wasn't there!");
×
124
                }
125
            }
126
        }
64,935✔
127
    }
64,935✔
128

129
    internal ConnectionReference DuplicateConnectionReference(ConnectionReference connectionReference)
130
    {
131
        var fileRef = connectionReference.FileReferenceCounter;
3✔
132

133
        if (fileRef.Database is null)
3!
134
            throw new InvalidOperationException(); //shouldn't happen if we already have a connection reference
×
135

136
        lock (fileRef)
3✔
137
        {
138
            var resultConnect = NativeMethods.Startup.DuckDBConnect(fileRef.Database, out var duplicatedNativeConnection);
3✔
139
            if (resultConnect.IsSuccess())
3!
140
            {
141
                fileRef.Increment();
3✔
142
            }
143
            else
144
            {
145
                throw new DuckDBException("DuckDBConnect failed");
×
146
            }
147
            return new ConnectionReference(fileRef, duplicatedNativeConnection);
3✔
148
        }
149
    }
3✔
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc