/// <summary>
        /// Open the environment.
        /// </summary>
        public void Open(EnvironmentOpenFlags openFlags = EnvironmentOpenFlags.None, UnixAccessMode accessMode = UnixAccessMode.Default)
        {
            if (IsOpened)
            {
                throw new InvalidOperationException("Environment is already opened.");
            }

            if (!openFlags.HasFlag(EnvironmentOpenFlags.NoSubDir) && !Directory.Exists(Path))
            {
                Directory.CreateDirectory(Path);
            }

            try
            {
                Lmdb.mdb_env_open(_handle, Path, openFlags, accessMode);
            }
            catch (Exception ex)
            {
                throw new LightningException($"Failed to open environment at path {Path}", ex);
            }

            IsOpened = true;
        }
Beispiel #2
0
 /// <summary>
 /// Abandon all the operations of the transaction instead of saving them.
 /// All cursors opened within the transaction will be closed by this call.
 /// The cursors and transaction handle will be freed and must not be used again after this call.
 /// </summary>
 public void Abort()
 {
     State = LightningTransactionState.Aborted;
     StateChanging?.Invoke(State);
     Lmdb.mdb_txn_abort(_handle);
 }
Beispiel #3
0
 /// <summary>
 /// Commit all the operations of a transaction into the database.
 /// All cursors opened within the transaction will be closed by this call.
 /// The cursors and transaction handle will be freed and must not be used again after this call.
 /// </summary>
 public void Commit()
 {
     State = LightningTransactionState.Commited;
     StateChanging?.Invoke(State);
     Lmdb.mdb_txn_commit(_handle);
 }
Beispiel #4
0
 /// <summary>
 /// Delete items from a database.
 /// This function removes key/data pairs from the database.
 /// If the database does not support sorted duplicate data items (MDB_DUPSORT) the data parameter is ignored.
 /// If the database supports sorted duplicates and the data parameter is NULL, all of the duplicate data items for the key will be deleted.
 /// Otherwise, if the data parameter is non-NULL only the matching data item will be deleted.
 /// This function will return MDB_NOTFOUND if the specified key/data pair is not in the database.
 /// </summary>
 /// <param name="db">A database handle returned by mdb_dbi_open()</param>
 /// <param name="key">The key to delete from the database</param>
 public void Delete(LightningDatabase db, byte[] key)
 {
     Lmdb.mdb_del(_handle, db.Handle(), key);
 }
        void RotateIfRequired()
        {
            if (_writtenSinceRotateCheck < _bufferSizeBytes / 10)
            {
                return;
            }

            _writtenSinceRotateCheck = 0;

            using (var tx = _env.BeginTransaction())
                using (var db = tx.OpenDatabase())
                {
                    int        err;
                    MDBEnvInfo estat;
                    if (0 != (err = Lmdb.mdb_env_info(_env.Handle(), out estat)))
                    {
                        throw new Exception(Lmdb.mdb_strerror(err));
                    }

                    MDBStat stat;
                    if (0 != (err = Lmdb.mdb_stat(tx.Handle(), db.Handle(), out stat)))
                    {
                        throw new Exception(Lmdb.mdb_strerror(err));
                    }

                    // http://www.openldap.org/lists/openldap-technical/201303/msg00145.html
                    // 1) MDB_stat gives you the page size.
                    // 2) MDB_envinfo tells the mapsize and the last_pgno.If you divide mapsize
                    //    by pagesize you'll get max pgno. The MAP_FULL error is returned when last_pgno reaches max pgno.

                    var targetPages = _bufferSizeBytes / stat.ms_psize;
                    if ((ulong)estat.me_last_pgno < targetPages && (double)(ulong)estat.me_last_pgno / targetPages < 0.75)
                    {
                        return;
                    }

                    var count = tx.GetEntriesCount(db);
                    if (count == 0)
                    {
                        Log.Warning("Attempting to rotate buffer but no events are present");
                        return;
                    }

                    var toPurge = Math.Max(count / 4, 1);
                    Log.Warning("Buffer is full; dropping {ToPurge} events to make room for new ones",
                                toPurge);

                    using (var cur = tx.CreateCursor(db))
                    {
                        cur.MoveToFirst();

                        for (var i = 0; i < toPurge; ++i)
                        {
                            cur.Delete();
                            cur.MoveNext();
                        }
                    }

                    tx.Commit();
                }
        }
        private static string mdb_strerror(int err)
        {
            var ptr = Lmdb.mdb_strerror(err);

            return(Marshal.PtrToStringAnsi(ptr));
        }
Beispiel #7
0
 /// <summary>
 /// Delete current key/data pair.
 /// This function deletes the key/data pair to which the cursor refers.
 /// </summary>
 /// <param name="option">Options for this operation. This parameter must be set to 0 or one of the values described here.
 ///     MDB_NODUPDATA - delete all of the data items for the current key. This flag may only be specified if the database was opened with MDB_DUPSORT.</param>
 private void Delete(CursorDeleteOption option)
 {
     Lmdb.mdb_cursor_del(_handle, option);
 }
Beispiel #8
0
 /// <summary>
 /// Store by cursor.
 /// This function stores key/data pairs into the database.
 /// If the function fails for any reason, the state of the cursor will be unchanged.
 /// If the function succeeds and an item is inserted into the database, the cursor is always positioned to refer to the newly inserted item.
 /// </summary>
 /// <param name="key">The key operated on.</param>
 /// <param name="values">The data items operated on.</param>
 public void PutMultiple(byte[] key, byte[][] values)
 {
     using (var marshal = new MarshalMultipleValueStructure(key, values))
         Lmdb.mdb_cursor_put(_handle, ref marshal.Key, marshal.Values, CursorPutOptions.MultipleData);
 }
Beispiel #9
0
 /// <summary>
 /// Store by cursor.
 /// This function stores key/data pairs into the database. The cursor is positioned at the new item, or on failure usually near it.
 /// Note: Earlier documentation incorrectly said errors would leave the state of the cursor unchanged.
 /// If the function fails for any reason, the state of the cursor will be unchanged.
 /// If the function succeeds and an item is inserted into the database, the cursor is always positioned to refer to the newly inserted item.
 /// </summary>
 /// <param name="key">The key operated on.</param>
 /// <param name="value">The data operated on.</param>
 /// <param name="options">
 /// Options for this operation. This parameter must be set to 0 or one of the values described here.
 ///     CursorPutOptions.Current - overwrite the data of the key/data pair to which the cursor refers with the specified data item. The key parameter is ignored.
 ///     CursorPutOptions.NoDuplicateData - enter the new key/data pair only if it does not already appear in the database. This flag may only be specified if the database was opened with MDB_DUPSORT. The function will return MDB_KEYEXIST if the key/data pair already appears in the database.
 ///     CursorPutOptions.NoOverwrite - enter the new key/data pair only if the key does not already appear in the database. The function will return MDB_KEYEXIST if the key already appears in the database, even if the database supports duplicates (MDB_DUPSORT).
 ///     CursorPutOptions.ReserveSpace - reserve space for data of the given size, but don't copy the given data. Instead, return a pointer to the reserved space, which the caller can fill in later. This saves an extra memcpy if the data is being generated later.
 ///     CursorPutOptions.AppendData - append the given key/data pair to the end of the database. No key comparisons are performed. This option allows fast bulk loading when keys are already known to be in the correct order. Loading unsorted keys with this flag will cause data corruption.
 ///     CursorPutOptions.AppendDuplicateData - as above, but for sorted dup data.
 /// </param>
 public void Put(byte[] key, byte[] value, CursorPutOptions options)
 {
     Lmdb.mdb_cursor_put(_handle, key, value, options);
 }
Beispiel #10
0
 private bool GetMultiple(CursorOperation operation)
 {
     return(Lmdb.mdb_cursor_get_multiple(_handle, ref _currentKeyStructure, ref _currentValueStructure, operation) == 0);
 }
Beispiel #11
0
 private bool Get(CursorOperation operation, byte[] key, byte[] value)
 {
     return(Lmdb.mdb_cursor_get(_handle, key, value, operation) == 0);
 }
Beispiel #12
0
 private bool Get(CursorOperation operation, byte[] key)
 {
     _currentValueStructure = default(ValueStructure);
     return(Lmdb.mdb_cursor_get(_handle, key, out _currentKeyStructure, out _currentValueStructure, operation) == 0);
 }
 /// <summary>
 /// Truncates all data from the database.
 /// </summary>
 public void Truncate(LightningTransaction transaction)
 {
     Lmdb.mdb_drop(transaction.Handle(), _handle, false);
 }
 /// <summary>
 /// Drops the database.
 /// </summary>
 public void Drop(LightningTransaction transaction)
 {
     Lmdb.mdb_drop(transaction.Handle(), _handle, true);
     IsOpened = false;
     _handle  = default(uint);
 }
 //TODO: tests
 /// <summary>
 /// Flush the data buffers to disk.
 /// Data is always written to disk when LightningTransaction.Commit is called, but the operating system may keep it buffered.
 /// MDB always flushes the OS buffers upon commit as well, unless the environment was opened with EnvironmentOpenFlags.NoSync or in part EnvironmentOpenFlags.NoMetaSync.
 /// </summary>
 /// <param name="force">If true, force a synchronous flush. Otherwise if the environment has the EnvironmentOpenFlags.NoSync flag set the flushes will be omitted, and with MDB_MAPASYNC they will be asynchronous.</param>
 public void Flush(bool force)
 {
     Lmdb.mdb_env_sync(_handle, force);
 }