Skip to content

nahcrof-code/nahcrofDB

Repository files navigation

Introduction

nahcrofDB is an open source, key-value database, designed to be simple, fast, and scalable, even in large datasets.

Installation

In order to install nahcrofDB, just run

git clone https://github.com/nahcrof-code/nahcrofDB.git

After installing, make sure that you have the required packages installed, the command for this is as follows.

pip install flask requests

Make sure to look through the config.txt file and update everything. "admin_password" is the password to acces the UI. "password_value" is the password used when accessing the database api.

Using database

in order to interact with the database, use client.py on the server that will be accessing the database server. If you are trying to directly interact with the database or create a new database you will use the cli on the server. To create a new database, you wil run...

Creating a database

python3 tools.py create_database DATABASE_NAME_HERE

for more commands use the "help" command, here is the output for the help command

Welcome to NahcrofDB
HINT: location is in reference to the folder the database is in.
reset <location> - resets database for specified location (ONLY USE IF COMPLETELY NECESSARY)
check - check the health of all databases and what keynames they have
structure <location> - view structure file of given location
file1 <location> - view first db file of given location
logs <location> - view log file of given location
fix_structure <location> - attempts to repair a corrupted structure file
view <location> - view database data
queue - view how many write requests are in the queue
folder <location> - view database folder for individual database
backup <location> - create a backup of an existing database
check_backup <location> - compare a database to it's corresponding backup
set_to_backup <location> - set the database to a pre-existing backup
create_database <folder_name> - creates empty database within specified folder
delete <location> - deletes database
st_size <location> - view the size of the structure file
partitions <location> - number of paritions
convert_structure <location> - converts old structure format
rebuild_all_structures - converts every structure file to new format
kill_db - safely shuts down the database program, flushing queue

Running the database

In order to run nahcrofDB you will run the following command.

python3 main.py

Please note that as of right now, nahcrofDB will only work in linux. Running "main.py" will start both the HTTP handler and "ferris." In short, ferris handles queued write requests.

Using client.py

client.py is the python api wrapper for nahcrofDB. To start, you will use the client.init function.

import client
client.init(folder="my_db_name", url="https://url.com/", password="api_password_here")

Making Keys

To make one key, you can do this.

client.makeKey("my_key", "my value")

To make multiple keys at once (less database strain) you can use the following function.

client.makeKeys({
    "key": "value",
    "key2": "value",
    "testkey": "testvalue"
})

Getting Keys

To get one key, you can use getKey

client.getKey("my_key")

OUTPUT:

my value

NOTE: if you attempt to use getKey and the key does not exist, the response will be as follows

{'error': True, 'message': 'Key (MISSING KEY) does not exist.', 'status': 404}

To get multiple keys, you can use getKeys

keys = client.getKeys("key", "key2")

OUTPUT:

{'key': 'value', 'key2': 'value'}

You can also use getKeysList which allows the user to get multiple keys using a list of keys instead of extra parameters.

keys = client.getKeysList(["key", "key2"])

OUTPUT:

{'key': 'value', 'key2': 'value'}

getKeysIncrements functions like getKeysList with the ability to get a list of keys, but instead of sending the entire request at once, it requests chunks, like requesting 100 keys out of the entire list at a time. This helps deal with the max GET request size you'll usually run into.

Here are some examples

keys = client.getKeysIncrements(["key", "key2", ...])

(this will get all the keys in increments of 100 and leave no logs)

keys = client.getKeysIncrements(["key", "key2", ...], log=True)

OUTPUT:

found values for 1/200 keys!
found values for 2/200 keys!
...
found values for 200/200 keys!

Finally, you can set increment to a value in order to search for a number other than 100 at a time. It looks like this...

client.getKeysIncrements(["key", "key2", ...], increment=50)

If this is too slow and you need to get a large number of values in one request, you can use postGetKeys like so:

client.postGetKeys(["key", "key2", ...])

(Note: in order to send this request, the database has to load the entirety of this data in memory, as will the client. Make sure the systems you are using are capable of sending and receiving these requests)

Searching the database

To find keys containing data within keynames, you will use the .searchNames function

client.searchNames("key")

OUTPUT:

['my_key', 'key', 'key2', testkey']

If you're looking for more precision in your search, change the "where" argument. Here's an example.

client.searchNames("key", where="start")

OUTPUT:

['key', 'key2']

Valid values for "where" include the following

"start", "end", None

these allow you to search the beginning of the key (where="start"), meaning that the key will only be included in the returned data if it's name starts with the query, the end of key (where="end"), anywhere within the key (None). If you do not specify where, it will be assumed that you are searching for all keys that contain the data somewhere within the name.

Incrementing values

In nahcrofDB, there is an incrementKey function. This allows you to increment a key, or a specific value within a key whilst only making one request to the database. Here is a simple example. (IMPORTANT: currently incrementKey does not support enterprise support)

client.makeKey("num", 5)
client.incrementKey(10, "num")
print(client.getKey("num"))

OUTPUT:

15

In this basic example, the key "num" was created and then incremented by 10. Here is a more complex example.

client.makeKey("nums", {
    "inner_values": [10, 23, 42, 8],
    "type": "int",
})
client.incrementKey(2, "nums", "inner_values", 3)
print(client.getKey("nums"))

OUTPUT

{
    "inner_values": [10, 23, 42, 10],
    "type": "int",
}

This change is because nahcrofDB was told to increment a value by 2, the value was in the path nums["inner_values"][3] which was the 4th value in "inner_values", or 8.

HTTP Docs

getting a key-value

GET /v2/key/:key/:database_folder

HEADERS:

X-API-Key: api-token-here

RESPONSE 200 OK

{
    "error": false,
    "message": null,
    "status": 200,
    "value": "value here"
}

getting multiple key-values

GET /v2/keys/:database_folder

QUERY PARAMS

?key[]=key1&key[]=key2&key[]=key3

HEADERS:

X-API-Key: api-token-here

RESPONSE 200 OK

{
    "key1": "val1"
    "key2": "val2"
    "key3": "val3"
    ...
}

Making key values

POST /v2/keys/:database_folder

BODY (application/json)

{
    "key": "val1"
    "key2": "val2"
    ...
}

RESPONSE 204 NO CONTENT

Searching your database

GET /v2/search/:database_folder

QUERY PARAMS

?query=Hello%20World

HEADERS:

X-API-Key: api-token-here

RESPONSE 200 OK

[
    "key1",
    "key2",
    ...
]

GET /v2/search/:database_folder

QUERY PARAMS

?query=1?where=end

HEADERS:

X-API-Key: api-token-here

RESPONSE 200 OK

[
    "key1",
    "test1",
    ...
]

Incrementing key values

POST /v2/increment/:database_folder/:path

BODY (application/json)

{
    "amount": 1
}

RESPONSE 204 NO CONTENT
example request url: /v2/increment/example_db/nums_list/num1

Backups/redundancy

Database Redundancy

This is built using the client.py script and is not actually built-in on the database side. If requested, I'd be willing to give a more thorough breakdown on how redundancy can be well handled purely on the client.

The config file to setup your redundancy wherever you happen to be using nahcrofDB is titled nahcrofDB_client_config.py. The absence of this file is the cause for the start message "Failure setting up enterprise usage" followed by an import error. Despite the comments within the file, do not include more than one redundant database. The functionality is not currently there.

nahcrofDB_client_config.py

# you do not need to use this file if you are not using enterprise mode, 
# this would be included with your client file if you are using enterprise mode.

# expand this list as much as you need, each database will be written to and utilized in the event of another database failure, 
# the one used in the init function will be the default
databases = [
    {"url": "http://0.0.0.0:8080", "password": "super_duper_password"}, 
]

as for using it within your code, everything stays the same except for the .init function which will look something like this now:

client.init(folder="my_db_name", url="https://url.com/", password="api_password_here", enterprise=True)

as long as enterprise is either not explicitly set or is intentionally set to False, redundant databases will be ignored and requests will ONLY go to the database configured in the init function.

Backup scripts

For this I'm just going to link to an external repo, there's already tons of files in this one and it kinda bothers me nahcrofDB-backup

Projects using nahcrofDB

  • CrofAI - Cheap, scalable AI inference provider
  • Rise-game - text-based, online, browser RPG game