forked from tpotlog/unqlitego
-
Notifications
You must be signed in to change notification settings - Fork 2
/
unqlite.go
175 lines (148 loc) · 4.7 KB
/
unqlite.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package unqlitego
// #include <unqlite.h>
// #include <wrappers.h>
// #include <stdlib.h>
import "C"
import (
"fmt"
"sync"
)
var (
lib *Library
)
// init will initialize the library.
// This is to replace to previous implementation of init for the UnQLite library.
// In order to be fully ThreadSafe the library itself requires a global Mutex.
//
// Calls to 'C.unqlite_lib_init()' are ThreadSafe and any subsequents call will result in NOOP.
// Calls to 'C.unqlite_lib_shutdown()' are NOT ThreadSafe and require a library Mutex.
// Any subsequent calls to 'C.unqlite_lib_shutdown()' will result in NOOP.
// Calls to 'unqlite_lib_config' are not ThreadSafe and require a library Mutex.
func init() {
lib = &Library{
mu: new(sync.Mutex),
}
}
// Library represents the UnQLite Library Control.
type Library struct {
// Is Initialized
init bool
// ThreadSafe Mutex
mu *sync.Mutex
}
// Info returns the UnQLite Library.
func Info() *Library {
return lib
}
// IsInitialized will return boolean indicating if the library is initialized.
func (l *Library) IsInitialized() bool {
l.mu.Lock()
defer l.mu.Unlock()
return l.init
}
// Init will initialize the library. After call init, the library must be shutdown first before any
// re-configuration can be done. Subsequent calls result in NOOP.
// This is autocalled when a database is opened.
func (l *Library) Init() {
// Initalize ThreadSafe Library Init.
l.mu.Lock()
defer l.mu.Unlock()
// Initialize Native Library
C.unqlite_lib_init()
l.init = true
}
// IsThreadSafe returns a boolean identifiying if the UnQLite library is
// compiled Thread Safe.
func (l *Library) IsThreadSafe() bool {
if !l.IsInitialized() {
l.Init()
}
return C.unqlite_lib_is_threadsafe() == 1
}
// Version returns the version string.
func (l *Library) Version() string {
return C.GoString(C.unqlite_lib_version())
}
// Signature returns the Signature string.
func (l *Library) Signature() string {
return C.GoString(C.unqlite_lib_signature())
}
// Ident returns the UnQLite identification string.
func (l *Library) Ident() string {
return C.GoString(C.unqlite_lib_ident())
}
// Copyright returns the Copyright string.
func (l *Library) Copyright() string {
return C.GoString(C.unqlite_lib_copyright())
}
// Shutdown the UnQLite Library.
func (l *Library) Shutdown() error {
// Enforce ThreadSafe operation.
l.mu.Lock()
defer l.mu.Unlock()
res := C.unqlite_lib_shutdown()
if res != C.UNQLITE_OK {
return UnQLiteError(res)
}
l.init = false
return nil
}
// UnQLiteError is returned on both UnQLite native errors as well as UnQLite Go errors.
// Native errors are within the range of '<= 0' (Equal and lesser then Zero) while the
// errors from UnQLite Go are > 0 (Greater then Zero).
//
// ( UnQLiteError <= 0 ) Native Errors
// ( UnQLiteError > 0 ) UnQLite Go Errors.
type UnQLiteError int
// Error returns the string representation of the UnQLiteError.
func (e UnQLiteError) Error() string {
s := errString[e]
if s == "" {
return fmt.Sprintf("err: %d", int(e))
}
return s
}
func (e UnQLiteError) String() string {
return e.Error()
}
var errString = map[UnQLiteError]string{
C.UNQLITE_OK: "OK",
C.UNQLITE_LOCKERR: "Locking protocol error",
C.UNQLITE_READ_ONLY: "Read only Key/Value storage engine",
C.UNQLITE_CANTOPEN: "Unable to open the database file",
C.UNQLITE_FULL: "Full database",
C.UNQLITE_VM_ERR: "Virtual machine error",
C.UNQLITE_COMPILE_ERR: "Compilation error",
C.UNQLITE_DONE: "Operation done", // Not an error.
C.UNQLITE_CORRUPT: "Corrupt pointer",
C.UNQLITE_NOOP: "No such method",
C.UNQLITE_PERM: "Permission error",
C.UNQLITE_EOF: "End Of Input",
C.UNQLITE_NOTIMPLEMENTED: "Method not implemented by the underlying Key/Value storage engine",
C.UNQLITE_BUSY: "The database file is locked",
C.UNQLITE_UNKNOWN: "Unknown configuration option",
C.UNQLITE_EXISTS: "Record exists",
C.UNQLITE_ABORT: "Another thread have released this instance",
C.UNQLITE_INVALID: "Invalid parameter",
C.UNQLITE_LIMIT: "Database limit reached",
C.UNQLITE_NOTFOUND: "No such record",
C.UNQLITE_LOCKED: "Forbidden Operation",
C.UNQLITE_EMPTY: "Empty record",
C.UNQLITE_IOERR: "IO error",
C.UNQLITE_NOMEM: "Out of memory",
}
// unQLiteValue represents an UnQLite Value object which is returned from the unlying UnQLite Database.
type unQLiteValue struct {
// Pointer to underlying UnQLite Value.
v *C.unqlite_value
}
// Nil returns a boolean indicating if the unQLiteValue is nil.
func (uv *unQLiteValue) Nil() bool {
switch uv.v {
case nil:
// User Data is wrong
return true
default:
return false
}
}