Skip to content

Commit

Permalink
Merge pull request #24 from saurabh0719/v0.5.2-develop
Browse files Browse the repository at this point in the history
V0.5.3
  • Loading branch information
saurabh0719 authored May 28, 2021
2 parents 7997509 + 86fec0a commit 1b37749
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 54 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Before contributing ensure you've read and understood the [documentation](https:
- If you're issuing a feature request, please mention why it will be useful or the use case it solves.
- If you intend to implement the new feature request OR fix a bug yourself, then give a brief outline of the proposed solution.

* Fork the `main` branch for making your changes.
* Fork the `main` branch and make your changes. Ensure that the new code is formatted with [black](https://pypi.org/project/black/)

* You can issue a new [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) to the `main` branch that closes the issue *after* you've been assigned.
- Any non-trivial pull request without having opened an earlier issue will be closed.
Expand Down
39 changes: 34 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
$ pip install elara
```

* Latest - `v0.5.2`
* Latest - `v0.5.3`

Go through the [release notes](#releases) for details on upgrades as breaking changes might happen between version upgrades while Elara is in beta.

Expand Down Expand Up @@ -113,7 +113,7 @@ Using `exe_secure()` without a key file or without the correct key file correspo
```python
import elara

db = elara.exe("new.db", "newdb.key") # commit=False
db = elara.exe_secure("new.db", "newdb.key") # commit=False

db.set("num", 20)

Expand Down Expand Up @@ -148,9 +148,15 @@ All the following operations are methods that can be applied to the instance ret
* `clear()` - clears the database data currently stored in-memory.
* `exists(key)` - returns `True` if the key exists.
* `commit()` - write in-memory changes into the database file.
<hr>

* `getset(key, value)` - Sets the new value and returns the old value for that key or returns `False`.
* `getkeys()` - returns the list of keys in the database with. The list is ordered with the `most recently accessed` keys starting from index 0.
* `numkeys()` - returns the number of keys in the database.
* `getmatch(match)` - Takes the `match` argument and returns a Dictionary of key-value pairs of which the keys contain `match` as a sub string.

<hr>

* `retkey()` - returns the Key used to encrypt/decrypt the db file; returns `None` if the file is unprotected.
* `retmem()` - returns all the in-memory db contents.
* `retdb()` - returns all the db file contents.
Expand Down Expand Up @@ -179,6 +185,28 @@ Note - `retmem()` and `retdb()` will return the same value if `commit` is set to

[Go back to the table of contents](#contents)


Elara adds some syntax sugar for get(), set() and rem() :

```python
import elara

db = elara.exe("new.db")

db["key"] = "value"

print(db["key"])
# value

del self.db["key"]

print(db.retmem())
# {}

```

[Go back to the table of contents](#contents)

<span id="cache"></span>
### Cache:

Expand Down Expand Up @@ -318,7 +346,7 @@ print(cache.get("obj").num)

* Elara uses checksums and a file version flag to verify database file integrity.

All database writes are atomic (uses the [safer](https://github.com/rec/safer) library).
All database writes are atomic (uses the [safer](https://github.com/rec/safer) library). Database writes are done in a separate thread along with a thread lock.

[Go back to the table of contents](#contents)

Expand Down Expand Up @@ -493,7 +521,8 @@ $ python -m unittest -v
## Release notes

* Latest - `v0.5.x`
- `v0.5.2` - No breaking changes
- `v0.5.3` - No breaking changes
- `v0.5.2`
- `v0.5.1`
- `v0.5.0`

Expand All @@ -507,7 +536,7 @@ $ python -m unittest -v

To safeguard data, its better to **export all existing data** from any existing database file before upgrading Elara. (use `exportdb(export_path)`).

View Elara's [release history](https://github.com/saurabh0719/elara/releases/).
View Elara's detailed [release history](https://github.com/saurabh0719/elara/releases/).

[Go back to the table of contents](#contents)

Expand Down
29 changes: 25 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ pushed into an upstream repository.
import elara
db = elara.exe("new.db", "newdb.key") # commit=False
db = elara.exe_secure("new.db", "newdb.key") # commit=False
db.set("num", 20)
Expand Down Expand Up @@ -141,6 +141,8 @@ file. Set the ``commit`` argument to ``True`` else manually use the
- ``getkeys()`` - returns the list of keys in the database with. The
list is ordered with the ``most recently accessed`` keys starting
from index 0.
- ``getmatch(match)`` - Takes the ``match`` argument and returns a
Dictionary of key-value pairs of which the keys contain ``match`` as a sub string.
- ``numkeys()`` - returns the number of keys in the database.
- ``retkey()`` - returns the Key used to encrypt/decrypt the db file;
returns ``None`` if the file is unprotected.
Expand Down Expand Up @@ -170,6 +172,24 @@ Note - ``retmem()`` and ``retdb()`` will return the same value if
``commit`` is set to ``True`` or if the ``commit()`` method is used
before calling ``retdb()``

Elara adds some syntax sugar for get(), set() and rem() :

.. code:: python
import elara
db = elara.exe("new.db")
db["key"] = "value"
print(db["key"])
# value
del self.db["key"]
print(db.retmem())
# {}
Cache:
~~~~~~

Expand Down Expand Up @@ -311,7 +331,7 @@ as long as they are ``in-memory`` and ``not persisted in the file``, as that wou
- To persist a simple object as a dictionary, use the ``__dict__`` attribute.
- Elara uses checksums and a file version flag to verify database file integrity.

All database writes are atomic (uses the safer library).
All database writes are atomic (uses the safer library). Database writes are done in a separate thread along with a thread lock.

API reference
-------------
Expand Down Expand Up @@ -522,7 +542,8 @@ Releases notes

- Latest - ``v0.5.x``

- ``v0.5.2`` - No breaking changes
- ``v0.5.3`` - No breaking changes
- ``v0.5.2``
- ``v0.5.1``
- ``v0.5.0``

Expand All @@ -538,7 +559,7 @@ instead.
To safeguard data, its better to export all existing data from any existing database file before upgrading Elara.
(using ``exportdb(export_path)``)

View Elara's release history
View Elara's detailed release history
`here <https://github.com/saurabh0719/elara/releases/>`__.


Expand Down
Binary file modified elara.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions elara/db_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""
Copyright (c) 2021, Saurabh Pujari
All rights reserved.
This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree.
"""


import threading


class DB_Thread(threading.Thread):
def run(self):
self.exception = None

try:
self.ret_val = self._target(*self._args)
except BaseException as e:
self.exception = e

def join(self):
super(DB_Thread, self).join()

if self.exception:
raise self.exception
return self.ret_val
79 changes: 64 additions & 15 deletions elara/elara.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree.
"""
import threading
from .db_thread import DB_Thread
import os
import atexit
from .elarautil import Util
from .exceptions import InvalidCacheParams
from .lru import LRU, Cache_obj
from .status import Status
from .exceptions import InvalidCacheParams


def is_pos(val):
Expand All @@ -18,38 +20,45 @@ def is_pos(val):

class Elara:

from .strings import setnx, append, getset, mget, mset, msetnx, slen
from .hashtables import hadd, haddt, hexists, hget, hkeys, hmerge, hnew, hpop, hvals
from .lists import (
lnew,
lpush,
lappend,
lexists,
lextend,
lindex,
linsert,
llen,
lnew,
lpop,
lpush,
lrange,
lrem,
lpop,
llen,
lappend,
lexists,
linsert,
)
from .hashtables import hnew, hadd, haddt, hget, hpop, hkeys, hvals, hexists, hmerge
from .shared import (
retmem,
retdb,
retkey,
commit,
exportdb,
exportkeys,
exportmem,
retdb,
retkey,
retmem,
securedb,
updatekey,
)
from .strings import append, getset, mget, mset, msetnx, setnx, slen

def __init__(self, path, commitdb, key_path=None, cache_param=None):
self.path = os.path.expanduser(path)
self.commitdb = commitdb
atexit.register(self._autocommit)

# Thread to write into the database
self.db_thread = None
self.db_lock = threading.Lock()

# Write data into the database on exit
atexit.register(self._autocommit)

if cache_param == None:
self.lru = LRU()
self.max_age = None
Expand Down Expand Up @@ -112,10 +121,28 @@ def _load(self):
self.lru._load(self.db, self.max_age)

def _dump(self):

if self.key:
Util.encrypt_and_store(self) # Enclose in try-catch
if self.db_thread is not None:
self.db_thread.join()

self.db_thread = DB_Thread(
target=Util.encrypt_and_store, args=(self, self.db_lock)
)
self.db_thread.start()
self.db_thread.join() # Enclose in try-catch
else:
Util.store_plain_db(self)

if self.db_thread is not None:
self.db_thread.join()

self.db_thread = DB_Thread(
target=Util.store_plain_db, args=(self, self.db_lock)
)
self.db_thread.start()
self.db_thread.join()

# Util.store_plain_db(self)

def _autocommit(self):
if self.commitdb:
Expand All @@ -140,6 +167,19 @@ def __delitem__(self, key):
def __contains__(self, key):
return self.exists(key)

# syntax sugar for get, set, rem and exists
def __getitem__(self, key):
return self.get(key)

def __setitem__(self, key, value):
return self.set(key, value)

def __delitem__(self, key):
return self.rem(key)

def __contains__(self, key):
return self.exists(key)

# Take max_age or self.max_age
def set(self, key, value, max_age=None):
if isinstance(key, str):
Expand Down Expand Up @@ -255,6 +295,15 @@ def getmatch(self, match):
return res


def getmatch(self, match):
deleted_keys, cache = self.lru.all()
self._remkeys_db_only(deleted_keys)
res = {}
for key, value in self.db.items():
if match in key:
res[key] = value
return res

def incr(self, key, val=1):
if self.exists(key):
data = self.get(key)
Expand Down
Loading

0 comments on commit 1b37749

Please sign in to comment.