     }
     
     open func valueExistsForKey(_ key: String) -> Bool {
-        guard let db = db else {
-            NSLog("Database reference is not existent (it has probably been closed)")
-            return false
-        }
-        var rawData: UnsafeMutableRawPointer? = nil
-        var rawDataLength: Int = 0
-        let status = levelDBItemGet(db, key.cString, key.count, &rawData, &rawDataLength)
-        if status == 0 {
-            free(rawData)
-            return true
-        } else {
-            return false
-        }
+        var result = false
+        levelDBQueue.sync {
+            guard let db = db else {
+                NSLog("Database reference is not existent (it has probably been closed)")
+                return
+            }
+            var rawData: UnsafeMutableRawPointer? = nil
+            var rawDataLength: Int = 0
+            let status = levelDBItemGet(db, key.cString, key.count, &rawData, &rawDataLength)
+            if status == 0 {
+                free(rawData)
+                result = true
+            }
+        }
+        return result
     }
     
     open func removeValueForKey(_ key: String) {
-        guard let db = db else {
-            NSLog("Database reference is not existent (it has probably been closed)")
-            return
-        }
-        let status = levelDBItemDelete(db, key.cString, key.count)
-        if status != 0 {
-            NSLog("Problem removing value with key: \(key) in database")
+        levelDBQueue.sync {
+            guard let db = db else {
+                NSLog("Database reference is not existent (it has probably been closed)")
+                return
+            }
+            let status = levelDBItemDelete(db, key.cString, key.count)
+            if status != 0 {
+                NSLog("Problem removing value with key: \(key) in database")
+            }
         }
     }
     

    }
    
    open func setValue(_ value: [String : Any]?, forKey key: String) {
        guard let db = db else {
            NSLog("Database reference is not existent (it has probably been closed)")
            return
        }
        if let newValue = value {
            var status = 0
            if var data = encoder(key, newValue) {
                data.withUnsafeMutableBytes { (mutableBytes: UnsafeMutablePointer<UInt8>) -> () in
                    status = levelDBItemPut(db, key.cString, key.count, mutableBytes, data.count)
                }
                if status != 0 {
                    NSLog("setValue: Problem storing key/value pair in database")
                }
            } else {
                NSLog("Error: setValue: encoder(key, newValue) returned nil, key: \(key), newValue: \(newValue)")
            }
        } else {
            //NSLog("setValue: newValue is nil")
            levelDBItemDelete(db, key.cString, key.count)
        }
    }
    

    }
    
    open func enumerateKeysWith(predicate: NSPredicate?, backward: Bool, startingAtKey key: String?, andPrefix prefix: String?, callback: LevelDBKeyCallback) {
        levelDBQueue.sync {
            guard let db = db else {
                NSLog("Database reference is not existent (it has probably been closed)")
                return
            }
            let iterator = levelDBIteratorNew(db)
            var stop = false
            guard let iteratorPointer = iterator else {
                NSLog("iterator is nil")
                return
            }
            _startIterator(iteratorPointer, backward: backward, prefix: prefix, start: key)
            while levelDBIteratorIsValid(iterator) {
                var iKey: UnsafeMutablePointer<Int8>? = nil
                var iKeyLength: Int = 0
                levelDBIteratorGetKey(iterator, &iKey, &iKeyLength)
                if let iKey = iKey {
                    if let prefix = prefix {
                        if memcmp(iKey, prefix.cString, min(prefix.count, iKeyLength)) != 0 {
                            break
                        }
                    }
                    let iKeyString = String.fromCString(iKey, length: iKeyLength)
                    if predicate != nil {
                        var iData: UnsafeMutableRawPointer? = nil
                        var iDataLength: Int = 0
                        levelDBIteratorGetValue(iterator, &iData, &iDataLength)
                        if let iData = iData {
                            let v = decoder(iKeyString, Data(bytes: iData, count: iDataLength))
                            if predicate!.evaluate(with: v) {
                                callback(iKeyString, &stop)
                            }
                        }
                    } else {
                        callback(iKeyString, &stop)
                    }
                }
                if stop {
                    break
                }
                backward ? levelDBIteratorMoveBackward(iterator) : levelDBIteratorMoveForward(iterator)
            }
            levelDBIteratorDelete(iterator)
        }
    }
    
    open func enumerateKeysAndValues(backward: Bool, startingAtKey key: String?, andPrefix prefix: String?, callback: LevelDBKeyValueCallback) {
        
        enumerateKeysAndValuesWith(predicate: nil, backward: backward, startingAtKey: key, andPrefix: prefix, callback: callback)
    }
    
    open func enumerateKeysAndValues(callback: LevelDBKeyValueCallback) {
        enumerateKeysAndValuesWith(predicate: nil, backward: false, startingAtKey: nil, andPrefix: nil, callback: callback)
    }
    
    open func enumerateKeysAndValuesWith(predicate: NSPredicate?, backward: Bool, startingAtKey key: String?, andPrefix prefix: String?, callback:LevelDBKeyValueCallback) {
        levelDBQueue.sync {
            guard let db = db else {
                NSLog("Database reference is not existent (it has probably been closed)")
                return
            }
            let iterator = levelDBIteratorNew(db)
            var stop = false
            guard let iteratorPointer = iterator else {
                NSLog("iterator is nil")
                return
            }
            _startIterator(iteratorPointer, backward: backward, prefix: prefix, start: key)
            while levelDBIteratorIsValid(iterator) {
                var iKey: UnsafeMutablePointer<Int8>? = nil
                var iKeyLength: Int = 0
                levelDBIteratorGetKey(iterator, &iKey, &iKeyLength);
                if let iKey = iKey {
                    if let prefix = prefix {
                        if memcmp(iKey, prefix.cString, min(prefix.count, iKeyLength)) != 0 {
                            break
                        }
                    }
                    let iKeyString = String.fromCString(iKey, length: iKeyLength)
                    var iData: UnsafeMutableRawPointer? = nil
                    var iDataLength: Int = 0
                    levelDBIteratorGetValue(iterator, &iData, &iDataLength)
                    if let iData = iData, let v = decoder(iKeyString, Data(bytes: iData, count: iDataLength)) {
                        if predicate != nil {
                            if predicate!.evaluate(with: v) {
                                callback(iKeyString, v, &stop)
                            }
                        } else {
                            callback(iKeyString, v, &stop)
                        }
                    }
                }
                if (stop) {
                    break;
                }
                backward ? levelDBIteratorMoveBackward(iterator) : levelDBIteratorMoveForward(iterator)
            }
            levelDBIteratorDelete(iterator);
        }
    }
    
    open func enumerateKeysAndValuesLazily(backward: Bool, startingAtKey key: String?, andPrefix prefix: String?, callback: LevelDBLazyKeyValueCallback) {
        levelDBQueue.sync {
            guard let db = db else {
                NSLog("Database reference is not existent (it has probably been closed)")
                return
            }
            let iterator = levelDBIteratorNew(db)
            var stop = false
            guard let iteratorPointer = iterator else {
                NSLog("iterator is nil")
                return
            }
            _startIterator(iteratorPointer, backward: backward, prefix: prefix, start: key)
            while levelDBIteratorIsValid(iterator) {
                var iKey: UnsafeMutablePointer<Int8>? = nil
                var iKeyLength: Int = 0
                levelDBIteratorGetKey(iterator, &iKey, &iKeyLength);
                if let iKey = iKey {
                    if let prefix = prefix {
                        if memcmp(iKey, prefix.cString, min(prefix.count, iKeyLength)) != 0 {
                            break
                        }
                    }
                    let iKeyString = String.fromCString(iKey, length: iKeyLength)
                    let getter : () -> [String : Any]? = {
                        var iData: UnsafeMutableRawPointer? = nil
                        var iDataLength: Int = 0
                        levelDBIteratorGetValue(iterator, &iData, &iDataLength);
                        if let iData = iData {
                            return self.decoder(iKeyString, Data(bytes: iData, count: iDataLength));
                        } else {
                            return nil
                        }
                    };
                    callback(iKeyString, getter, &stop);
                }
                if (stop) {
                    break;
                }
                backward ? levelDBIteratorMoveBackward(iterator) : levelDBIteratorMoveForward(iterator)
            }
            levelDBIteratorDelete(iterator);
        }
    }
    
    // MARK: - Helper methods
    
    open func deleteDatabaseFromDisk() {
        self.close()
        levelDBQueue.sync {
            do {
                let fileManager = FileManager.default
                try fileManager.removeItem(atPath: path)
            } catch {
                NSLog("error deleting database at path \(path), \(error)")
            }
        }
    }
    
    public func open() {
        levelDBQueue.sync {
            self.db = levelDBOpen(path.cString)
        }
    }
    
    open func close() {
        levelDBQueue.sync {
            if let db = db {
                levelDBDelete(db)
                self.db = nil
            }
        }
    }
    
