1package forestdb
2
3//  Copyright (c) 2014 Couchbase, Inc.
4//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5//  except in compliance with the License. You may obtain a copy of the License at
6//    http://www.apache.org/licenses/LICENSE-2.0
7//  Unless required by applicable law or agreed to in writing, software distributed under the
8//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
9//  either express or implied. See the License for the specific language governing permissions
10//  and limitations under the License.
11
12//#include <stdlib.h>
13//#include <libforestdb/forestdb.h>
14//#include "log.h"
15//extern void LogCallbackInternal(int, char*, char*);
16//void log_callback(int errcode, char *msg, void *ctx) {
17//    LogCallbackInternal(errcode, msg, ctx);
18//}
19//extern void FatalErrorCallbackInternal();
20//void gofatal_error_callback() {
21//    FatalErrorCallbackInternal();
22//}
23//extern fdb_compact_decision CompactionCallbackInternal(fdb_file_handle*, int, const char*, fdb_doc*,
24//                                                       uint64_t, uint64_t, void*);
25//fdb_compact_decision compaction_callback(fdb_file_handle *fhandle,
26//                                         fdb_compaction_status status,
27//                                         const char *kv_store_name,
28//                                         fdb_doc *doc,
29//                                         uint64_t last_oldfile_offset,
30//                                         uint64_t last_newfile_offset,
31//                                         void *ctx) {
32//    return CompactionCallbackInternal(fhandle, status, kv_store_name, doc, last_oldfile_offset,
33//                                      last_newfile_offset, ctx);
34//}
35import "C"
36
37import "unsafe"
38
39// KVStore handle
40type KVStore struct {
41	f    *File
42	db   *C.fdb_kvs_handle
43	name string
44}
45
46// File returns the File containing this KVStore
47func (k *KVStore) File() *File {
48	return k.f
49}
50
51// Handle returns the underlying fdb_kvs_handle for advanced uses.
52func (k *KVStore) Handle() *C.fdb_kvs_handle {
53	return k.db
54}
55
56// Close the KVStore and release related resources.
57func (k *KVStore) Close() error {
58	Log.Tracef("fdb_kvs_close call k:%p db:%p", k, k.db)
59	errNo := C.fdb_kvs_close(k.db)
60	Log.Tracef("fdb_kvs_close retn k:%p errNo:%v", k, errNo)
61	if errNo != RESULT_SUCCESS {
62		return Error(errNo)
63	}
64	return nil
65}
66
67// Info returns the information about a given kvstore
68func (k *KVStore) Info() (*KVStoreInfo, error) {
69	rv := KVStoreInfo{}
70	Log.Tracef("fdb_get_kvs_info call k:%p db:%p", k, k.db)
71	errNo := C.fdb_get_kvs_info(k.db, &rv.info)
72	Log.Tracef("fdb_kvs_close retn k:%p errNo:%v info:%v", k, errNo, rv.info)
73	if errNo != RESULT_SUCCESS {
74		return nil, Error(errNo)
75	}
76	return &rv, nil
77}
78
79// OpsInfo returns the information about the ops on given kvstore
80func (k *KVStore) OpsInfo() (*KVSOpsInfo, error) {
81	rv := KVSOpsInfo{}
82	Log.Tracef("fdb_get_kvs_ops_info call k:%p db:%p", k, k.db)
83	errNo := C.fdb_get_kvs_ops_info(k.db, &rv.info)
84	Log.Tracef("fdb_get_kvs_ops_info k:%p errNo:%v info:%v", k, errNo, rv.info)
85	if errNo != RESULT_SUCCESS {
86		return nil, Error(errNo)
87	}
88	return &rv, nil
89}
90
91// Get retrieves the metadata and doc body for a given key
92func (k *KVStore) Get(doc *Doc) error {
93	Log.Tracef("fdb_get call k:%p db:%p doc:%v", k, k.db, doc.doc)
94	errNo := C.fdb_get(k.db, doc.doc)
95	Log.Tracef("fdb_get retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
96	if errNo != RESULT_SUCCESS {
97		return Error(errNo)
98	}
99	return nil
100}
101
102// GetMetaOnly retrieves the metadata for a given key
103func (k *KVStore) GetMetaOnly(doc *Doc) error {
104	Log.Tracef("fdb_get_metaonly call k:%p db:%p doc:%v", k, k.db, doc.doc)
105	errNo := C.fdb_get_metaonly(k.db, doc.doc)
106	Log.Tracef("fdb_get_metaonly retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
107	if errNo != RESULT_SUCCESS {
108		return Error(errNo)
109	}
110	return nil
111}
112
113// GetBySeq retrieves the metadata and doc body for a given sequence number
114func (k *KVStore) GetBySeq(doc *Doc) error {
115	Log.Tracef("fdb_get_byseq call k:%p db:%p doc:%v", k, k.db, doc.doc)
116	errNo := C.fdb_get_byseq(k.db, doc.doc)
117	Log.Tracef("fdb_get_byseq retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
118	if errNo != RESULT_SUCCESS {
119		return Error(errNo)
120	}
121	return nil
122}
123
124// GetMetaOnlyBySeq retrieves the metadata for a given sequence number
125func (k *KVStore) GetMetaOnlyBySeq(doc *Doc) error {
126	Log.Tracef("fdb_get_metaonly_byseq call k:%p db:%p doc:%v", k, k.db, doc.doc)
127	errNo := C.fdb_get_metaonly_byseq(k.db, doc.doc)
128	Log.Tracef("fdb_get_metaonly_byseq retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
129	if errNo != RESULT_SUCCESS {
130		return Error(errNo)
131	}
132	return nil
133}
134
135// GetByOffset retrieves a doc's metadata and body with a given doc offset in the database file
136func (k *KVStore) GetByOffset(doc *Doc) error {
137	Log.Tracef("fdb_get_byoffset call k:%p db:%p doc:%v", k, k.db, doc.doc)
138	errNo := C.fdb_get_byoffset(k.db, doc.doc)
139	Log.Tracef("fdb_get_byoffset retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
140	if errNo != RESULT_SUCCESS {
141		return Error(errNo)
142	}
143	return nil
144}
145
146// Set update the metadata and doc body for a given key
147func (k *KVStore) Set(doc *Doc) error {
148	Log.Tracef("fdb_set call k:%p db:%p doc:%v", k, k.db, doc.doc)
149	errNo := C.fdb_set(k.db, doc.doc)
150	Log.Tracef("fdb_set retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
151	if errNo != RESULT_SUCCESS {
152		return Error(errNo)
153	}
154	return nil
155}
156
157// Delete deletes a key, its metadata and value
158func (k *KVStore) Delete(doc *Doc) error {
159	Log.Tracef("fdb_del call k:%p db:%p doc:%v", k, k.db, doc.doc)
160	errNo := C.fdb_del(k.db, doc.doc)
161	Log.Tracef("fdb_set retn k:%p errNo:%v doc:%v", k, errNo, doc.doc)
162	if errNo != RESULT_SUCCESS {
163		return Error(errNo)
164	}
165	return nil
166}
167
168// Shutdown destroys all the resources (e.g., buffer cache, in-memory WAL indexes, daemon compaction thread, etc.) and then shutdown the ForestDB engine
169func Shutdown() error {
170	Log.Tracef("fdb_shutdown call")
171	errNo := C.fdb_shutdown()
172	Log.Tracef("fdb_shutdown retn errNo:%v", errNo)
173	if errNo != RESULT_SUCCESS {
174		return Error(errNo)
175	}
176	return nil
177}
178
179type logContext struct {
180	callback *LogCallback
181	name     string
182	userCtx  interface{}
183}
184
185// Hold references to log callbacks and contexts.
186var logCallbacks []LogCallback
187var logContexts []interface{}
188
189func registerLogCallback(cb LogCallback, ctx interface{}) int {
190	logCallbacks = append(logCallbacks, cb)
191	logContexts = append(logContexts, ctx)
192	return len(logCallbacks) - 1
193}
194
195func (k *KVStore) SetLogCallback(l LogCallback, userCtx interface{}) {
196	var ctx C.log_context
197	ctx.offset = C.int(registerLogCallback(l, userCtx))
198	ctx.name = C.CString(k.name)
199	C.fdb_set_log_callback(k.db, C.fdb_log_callback(C.log_callback), unsafe.Pointer(&ctx))
200}
201
202func SetFatalErrorCallback(callback FatalErrorCallback) {
203	fatalErrorCallback = callback
204	C.fdb_set_fatal_error_callback(C.fdb_fatal_error_callback(C.gofatal_error_callback))
205}
206
207type FatalErrorCallback func()
208
209var fatalErrorCallback FatalErrorCallback
210
211type LogCallback func(name string, errCode int, msg string, ctx interface{})
212
213func LoggingLogCallback(name string, errCode int, msg string, ctx interface{}) {
214	Log.Errorf("ForestDB (%s) Error Code: %d Message: %s", name, errCode, msg)
215}
216