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

Giorgi / DuckDB.NET / 10110093053

26 Jul 2024 10:52AM UTC coverage: 90.226% (-0.03%) from 90.251%
10110093053

push

github

Giorgi
Set error type on exception

845 of 963 branches covered (87.75%)

Branch coverage included in aggregate %.

6 of 10 new or added lines in 3 files covered. (60.0%)

1 existing line in 1 file now uncovered.

1712 of 1871 relevant lines covered (91.5%)

794651.43 hits per line

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

86.87
/DuckDB.NET.Data/Internal/ConnectionManager.cs
1
using System;
2
using System.Collections.Concurrent;
3
using System.Runtime.InteropServices;
4
using System.Text;
5
using System.Threading;
6
using DuckDB.NET.Data.ConnectionString;
7
using DuckDB.NET.Native;
8

9
namespace DuckDB.NET.Data.Internal;
10

11
/// <summary>
12
/// Creates, caches, and disconnects ConnectionReferences.
13
/// </summary>
14
internal class ConnectionManager
15
{
16
    public static readonly ConnectionManager Default = new();
3✔
17

18
    private static readonly ConcurrentDictionary<string, FileRef> ConnectionCache = new(StringComparer.OrdinalIgnoreCase);
3✔
19

20
    internal ConnectionReference GetConnectionReference(DuckDBConnectionString connectionString)
21
    {
22
        var filename = connectionString.DataSource;
64,908✔
23

24
        var fileRef = connectionString.InMemory && !connectionString.Shared ? new FileRef("") : null;
64,908✔
25

26
        //need to loop until we have a locked fileRef
27
        //that is also in the cache
28
        while (fileRef == null)
65,084✔
29
        {
30
            fileRef = ConnectionCache.GetOrAdd(filename, fn =>
64,889✔
31
            {
64,889✔
32
                fileRef = new FileRef(filename);
51,644✔
33
                return fileRef;
51,644✔
34
            });
64,889✔
35

36
            Monitor.Enter(fileRef);
64,889✔
37

38
            //Need to make sure what we have locked is still in the cache
39
            var existingFileRef = ConnectionCache.GetOrAdd(filename, fileRef);
64,889✔
40

41
            if (existingFileRef == fileRef)
64,889✔
42
            {
43
                //file in the cache matches what is locked, we are good!
44
                break;
45
            }
46

47
            //exit lock and try the whole thing again
48
            Monitor.Exit(fileRef);
176✔
49
            fileRef = null;
176✔
50
        }
51

52
        //now connect what needs to be connected
53
        try
54
        {
55
            if (fileRef.Database == null)
64,908✔
56
            {
57
                var path = connectionString.InMemory ? null : filename;
56,603✔
58

59
                NativeMethods.Configuration.DuckDBCreateConfig(out var config);
56,603✔
60
                using (config)
56,603✔
61
                {
62
                    foreach (var (option, value) in connectionString.Configuration)
113,290✔
63
                    {
64
                        var state = NativeMethods.Configuration.DuckDBSetConfig(config, option, value);
45✔
65

66
                        if (!state.IsSuccess())
45✔
67
                        {
68
                            throw new DuckDBException($"Error setting '{option}' to '{value}'");
6✔
69
                        }
70
                    }
71

72
                    using var pathUnmanaged = path.ToUnmanagedString();
56,597✔
73

74
                    var resultOpen = NativeMethods.Startup.DuckDBOpen(pathUnmanaged, out var db, config, out var error);
56,597✔
75

76
                    if (!resultOpen.IsSuccess())
56,597!
77
                    {
NEW
78
                        throw new DuckDBException($"DuckDBOpen failed: {error.ToManagedString()}");
×
79
                    }
80
                    fileRef.Database = db; 
56,597✔
81
                }
82
            }
83

84
            var resultConnect = NativeMethods.Startup.DuckDBConnect(fileRef.Database, out var nativeConnection);
64,902✔
85

86
            if (resultConnect.IsSuccess())
64,902!
87
            {
88
                fileRef.Increment();
64,902✔
89
            }
90
            else
91
            {
NEW
92
                throw new DuckDBException("DuckDBConnect failed");
×
93
            }
94

95
            return new ConnectionReference(fileRef, nativeConnection);
64,902✔
96
        }
97
        finally
98
        {
99
            if (Monitor.IsEntered(fileRef))
64,908✔
100
            {
101
                Monitor.Exit(fileRef);
64,713✔
102
            }
103
        }
64,908✔
104
    }
64,902✔
105

106
    internal void ReturnConnectionReference(ConnectionReference connectionReference)
107
    {
108
        var fileRef = connectionReference.FileRefCounter;
64,899✔
109

110
        lock (fileRef)
64,899✔
111
        {
112
            var nativeConnection = connectionReference.NativeConnection;
64,899✔
113

114
            nativeConnection.Dispose();
64,899✔
115

116
            var current = fileRef.Decrement();
64,899✔
117

118
            if (current < 0)
64,899!
119
            {
120
                throw new InvalidOperationException($"{fileRef.FileName} has been returned too many times");
×
121
            }
122

123
            if (current == 0)
64,899✔
124
            {
125
                fileRef.Database?.Dispose();
56,591!
126
                fileRef.Database = null;
56,591✔
127

128
                if (!string.IsNullOrEmpty(fileRef.FileName) && !ConnectionCache.TryRemove(fileRef.FileName, out _))
56,591!
129
                {
130
                    throw new InvalidOperationException($"Internal Error: tried to remove {fileRef.FileName} from cache but it wasn't there!");
×
131
                }
132
            }
133
        }
64,899✔
134
    }
64,899✔
135

136
    internal ConnectionReference DuplicateConnectionReference(ConnectionReference connectionReference)
137
    {
138
        var fileRef = connectionReference.FileRefCounter;
3✔
139

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

143
        lock (fileRef)
3✔
144
        {
145
            var resultConnect = NativeMethods.Startup.DuckDBConnect(fileRef.Database, out var duplicatedNativeConnection);
3✔
146
            if (resultConnect.IsSuccess())
3!
147
            {
148
                fileRef.Increment();
3✔
149
            }
150
            else
151
            {
NEW
152
                throw new DuckDBException("DuckDBConnect failed");
×
153
            }
154
            return new ConnectionReference(fileRef, duplicatedNativeConnection);
3✔
155
        }
156
    }
3✔
157
}
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

© 2025 Coveralls, Inc