aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_db_util.h
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_db_util.h')
-rw-r--r--erts/emulator/beam/erl_db_util.h405
1 files changed, 405 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
new file mode 100644
index 0000000000..4fc7b4f52e
--- /dev/null
+++ b/erts/emulator/beam/erl_db_util.h
@@ -0,0 +1,405 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef _DB_UTIL_H
+#define _DB_UTIL_H
+
+#include "global.h"
+#include "erl_message.h"
+
+/*#define HARDDEBUG 1*/
+
+#ifdef DEBUG
+/*
+** DMC_DEBUG does NOT need DEBUG, but DEBUG needs DMC_DEBUG
+*/
+#define DMC_DEBUG 1
+#endif
+
+/*
+ * These values can be returned from the functions performing the
+ * BIF operation for different types of tables. When the
+ * actual operations have been performed, the BIF function
+ * checks for negative returns and issues BIF_ERRORS based
+ * upon these values.
+ */
+#define DB_ERROR_NONE 0 /* No error */
+#define DB_ERROR_BADITEM -1 /* The item was malformed ie no
+ tuple or to small*/
+#define DB_ERROR_BADTABLE -2 /* The Table is inconsisitent */
+#define DB_ERROR_SYSRES -3 /* Out of system resources */
+#define DB_ERROR_BADKEY -4 /* Returned if a key that should
+ exist does not. */
+#define DB_ERROR_BADPARAM -5 /* Returned if a specified slot does
+ not exist (hash table only) or
+ the state parameter in db_match_object
+ is broken.*/
+#define DB_ERROR_UNSPEC -10 /* Unspecified error */
+
+
+/*
+ * A datatype for a database entry stored out of a process heap
+ */
+typedef struct db_term {
+ ErlOffHeap off_heap; /* Off heap data for term. */
+ Uint size; /* Size of term in "words" */
+ Eterm tpl[1]; /* Untagged "constant pointer" to top tuple */
+ /* (assumed to be first in buffer) */
+} DbTerm;
+
+/* "Assign" a value to DbTerm.tpl */
+#define DBTERM_SET_TPL(dbtermPtr,tplPtr) ASSERT((tplPtr)==(dbtermPtr->tpl))
+/* Get start of term buffer */
+#define DBTERM_BUF(dbtermPtr) ((dbtermPtr)->tpl)
+
+union db_table;
+typedef union db_table DbTable;
+
+/* Info about a database entry while it's being updated
+ * (by update_counter or update_element)
+ */
+typedef struct {
+ DbTable* tb;
+ DbTerm* dbterm;
+ void** bp; /* {Hash|Tree}DbTerm** */
+ Uint new_size;
+ int mustResize;
+ void* lck;
+} DbUpdateHandle;
+
+
+typedef struct db_table_method
+{
+ int (*db_create)(Process *p, DbTable* tb);
+ int (*db_first)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm* ret /* [out] */);
+ int (*db_next)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm key, /* [in] */
+ Eterm* ret /* [out] */);
+ int (*db_last)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm* ret /* [out] */);
+ int (*db_prev)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm key,
+ Eterm* ret);
+ int (*db_put)(DbTable* tb, /* [in out] */
+ Eterm obj,
+ int key_clash_fail); /* DB_ERROR_BADKEY if key exists */
+ int (*db_get)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm key,
+ Eterm* ret);
+ int (*db_get_element)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm key,
+ int index,
+ Eterm* ret);
+ int (*db_member)(DbTable* tb, /* [in out] */
+ Eterm key,
+ Eterm* ret);
+ int (*db_erase)(DbTable* tb, /* [in out] */
+ Eterm key,
+ Eterm* ret);
+ int (*db_erase_object)(DbTable* tb, /* [in out] */
+ Eterm obj,
+ Eterm* ret);
+ int (*db_slot)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm slot,
+ Eterm* ret);
+ int (*db_select_chunk)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm pattern,
+ Sint chunk_size,
+ int reverse,
+ Eterm* ret);
+ int (*db_select)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm pattern,
+ int reverse,
+ Eterm* ret);
+ int (*db_select_delete)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm pattern,
+ Eterm* ret);
+ int (*db_select_continue)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm continuation,
+ Eterm* ret);
+ int (*db_select_delete_continue)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm continuation,
+ Eterm* ret);
+ int (*db_select_count)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm pattern,
+ Eterm* ret);
+ int (*db_select_count_continue)(Process* p,
+ DbTable* tb, /* [in out] */
+ Eterm continuation,
+ Eterm* ret);
+
+ int (*db_delete_all_objects)(Process* p,
+ DbTable* db /* [in out] */ );
+
+ int (*db_free_table)(DbTable* db /* [in out] */ );
+ int (*db_free_table_continue)(DbTable* db); /* [in out] */
+
+ void (*db_print)(int to,
+ void* to_arg,
+ int show,
+ DbTable* tb /* [in out] */ );
+
+ void (*db_foreach_offheap)(DbTable* db, /* [in out] */
+ void (*func)(ErlOffHeap *, void *),
+ void *arg);
+ void (*db_check_table)(DbTable* tb);
+
+ /* Lookup a dbterm for updating. Return false if not found.
+ */
+ int (*db_lookup_dbterm)(DbTable*, Eterm key,
+ DbUpdateHandle* handle); /* [out] */
+
+ /* Must be called for each db_lookup_dbterm that returned true,
+ ** even if dbterm was not updated.
+ */
+ void (*db_finalize_dbterm)(DbUpdateHandle* handle);
+
+} DbTableMethod;
+
+/*
+ * This structure contains data for all different types of database
+ * tables. Note that these fields must match the same fields
+ * in the table-type specific structures.
+ * The reason it is placed here and not in db.h is that some table
+ * operations may be the same on different types of tables.
+ */
+
+typedef struct db_fixation {
+ Eterm pid;
+ Uint counter;
+ struct db_fixation *next;
+} DbFixation;
+
+
+typedef struct db_table_common {
+ erts_refc_t ref;
+ erts_refc_t fixref; /* fixation counter */
+#ifdef ERTS_SMP
+ erts_smp_rwmtx_t rwlock; /* rw lock on table */
+ erts_smp_mtx_t fixlock; /* Protects fixations,megasec,sec,microsec */
+ int is_thread_safe; /* No fine locking inside table needed */
+ Uint32 type; /* table type, *read only* after creation */
+#endif
+ Eterm owner; /* Pid of the creator */
+ Eterm heir; /* Pid of the heir */
+ Eterm heir_data; /* To send in ETS-TRANSFER (is_immed or (DbTerm*) */
+ SysTimeval heir_started; /* To further identify the heir */
+ Eterm the_name; /* an atom */
+ Eterm id; /* atom | integer */
+ DbTableMethod* meth; /* table methods */
+ erts_smp_atomic_t nitems; /* Total number of items in table */
+ erts_smp_atomic_t memory_size;/* Total memory size. NOTE: in bytes! */
+ Uint megasec,sec,microsec; /* Last fixation time */
+ DbFixation* fixations; /* List of processes who have done safe_fixtable,
+ "local" fixations not included. */
+ /* All 32-bit fields */
+ Uint32 status; /* bit masks defined below */
+ int slot; /* slot index in meta_main_tab */
+ int keypos; /* defaults to 1 */
+} DbTableCommon;
+
+/* These are status bit patterns */
+#define DB_NORMAL (1 << 0)
+#define DB_PRIVATE (1 << 1)
+#define DB_PROTECTED (1 << 2)
+#define DB_PUBLIC (1 << 3)
+#define DB_BAG (1 << 4)
+#define DB_SET (1 << 5)
+/*#define DB_LHASH (1 << 6)*/
+#define DB_FINE_LOCKED (1 << 7) /* fine grained locking enabled */
+#define DB_DUPLICATE_BAG (1 << 8)
+#define DB_ORDERED_SET (1 << 9)
+#define DB_DELETE (1 << 10) /* table is being deleted */
+
+#define ERTS_ETS_TABLE_TYPES (DB_BAG|DB_SET|DB_DUPLICATE_BAG|DB_ORDERED_SET|DB_FINE_LOCKED)
+
+#define IS_HASH_TABLE(Status) (!!((Status) & \
+ (DB_BAG | DB_SET | DB_DUPLICATE_BAG)))
+#define IS_TREE_TABLE(Status) (!!((Status) & \
+ DB_ORDERED_SET))
+#define NFIXED(T) (erts_refc_read(&(T)->common.fixref,0))
+#define IS_FIXED(T) (NFIXED(T) != 0)
+
+Eterm erts_ets_copy_object(Eterm, Process*);
+
+/* optimised version of copy_object (normal case? atomic object) */
+#define COPY_OBJECT(obj, p, objp) \
+ if (IS_CONST(obj)) { *(objp) = (obj); } \
+ else { *objp = erts_ets_copy_object(obj, p); }
+
+#define DB_READ (DB_PROTECTED|DB_PUBLIC)
+#define DB_WRITE DB_PUBLIC
+#define DB_INFO (DB_PROTECTED|DB_PUBLIC|DB_PRIVATE)
+
+/* tb is an DbTableCommon and obj is an Eterm (tagged) */
+#define TERM_GETKEY(tb, obj) db_getkey((tb)->common.keypos, (obj))
+
+#define ONLY_WRITER(P,T) (((T)->common.status & (DB_PRIVATE|DB_PROTECTED)) \
+ && (T)->common.owner == (P)->id)
+
+#define ONLY_READER(P,T) (((T)->common.status & DB_PRIVATE) && \
+(T)->common.owner == (P)->id)
+
+/* Function prototypes */
+Eterm db_get_trace_control_word_0(Process *p);
+Eterm db_set_trace_control_word_1(Process *p, Eterm val);
+
+void db_initialize_util(void);
+Eterm db_getkey(int keypos, Eterm obj);
+void db_free_term_data(DbTerm* p);
+void* db_get_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj);
+int db_has_variable(Eterm obj);
+int db_is_variable(Eterm obj);
+void db_do_update_element(DbUpdateHandle* handle,
+ Sint position,
+ Eterm newval);
+void db_finalize_update_element(DbUpdateHandle* handle);
+Eterm db_add_counter(Eterm** hpp, Eterm counter, Eterm incr);
+Eterm db_match_set_lint(Process *p, Eterm matchexpr, Uint flags);
+Binary *db_match_set_compile(Process *p, Eterm matchexpr,
+ Uint flags);
+void erts_db_match_prog_destructor(Binary *);
+
+typedef struct match_prog {
+ ErlHeapFragment *term_save; /* Only if needed, a list of message
+ buffers for off heap copies
+ (i.e. binaries)*/
+ int single_variable; /* ets:match needs to know this. */
+ int num_bindings; /* Size of heap */
+ /* The following two are only filled in when match specs
+ are used for tracing */
+ struct erl_heap_fragment *saved_program_buf;
+ Eterm saved_program;
+ Uint heap_size; /* size of: heap + eheap + stack */
+ Uint eheap_offset;
+ Uint stack_offset;
+#ifdef DMC_DEBUG
+ Uint* prog_end; /* End of program */
+#endif
+ Uint text[1]; /* Beginning of program */
+} MatchProg;
+
+/*
+ * The heap-eheap-stack block of a MatchProg is nowadays allocated
+ * when the match program is run.
+ * - heap: variable bindings
+ * - eheap: erlang heap storage
+ * - eheap: a "large enough" stack
+ */
+
+#define DMC_ERR_STR_LEN 100
+
+typedef enum { dmcWarning, dmcError} DMCErrorSeverity;
+
+typedef struct dmc_error {
+ char error_string[DMC_ERR_STR_LEN + 1]; /* printf format string
+ with %d for the variable
+ number (if applicable) */
+ int variable; /* -1 if no variable is referenced
+ in error string */
+ struct dmc_error *next;
+ DMCErrorSeverity severity; /* Error or warning */
+} DMCError;
+
+typedef struct dmc_err_info {
+ unsigned int *var_trans; /* Translations of variable names,
+ initiated to NULL
+ and free'd with sys_free if != NULL
+ after compilation */
+ int num_trans;
+ int error_added; /* indicates if the error list contains
+ any fatal errors (dmcError severity) */
+ DMCError *first; /* List of errors */
+} DMCErrInfo;
+
+/*
+** Compilation flags
+**
+** The dialect is in the 3 least significant bits and are to be interspaced by
+** by at least 2 (decimal), thats why ((Uint) 2) isn't used. This is to be
+** able to add DBIF_GUARD or DBIF BODY to it to use in the match_spec bif
+** table. The rest of the word is used like ordinary flags, one bit for each
+** flag. Note that DCOMP_TABLE and DCOMP_TRACE are mutually exclusive.
+*/
+#define DCOMP_TABLE ((Uint) 1) /* Ets and dets. The body returns a value,
+ * and the parameter to the execution is a tuple. */
+#define DCOMP_TRACE ((Uint) 4) /* Trace. More functions are allowed, and the
+ * parameter to the execution will be an array. */
+#define DCOMP_DIALECT_MASK ((Uint) 0x7) /* To mask out the bits marking
+ dialect */
+#define DCOMP_FAKE_DESTRUCTIVE ((Uint) 8) /* When this is active, no setting of
+ trace control words or seq_trace tokens will be done. */
+
+
+Binary *db_match_compile(Eterm *matchexpr, Eterm *guards,
+ Eterm *body, int num_matches,
+ Uint flags,
+ DMCErrInfo *err_info);
+/* Returns newly allocated MatchProg binary with refc == 0*/
+Eterm db_prog_match(Process *p, Binary *prog, Eterm term, int arity,
+ Uint32 *return_flags /* Zeroed on enter */);
+/* returns DB_ERROR_NONE if matches, 1 if not matches and some db error on
+ error. */
+DMCErrInfo *db_new_dmc_err_info(void);
+/* Returns allocated error info, where errors are collected for lint. */
+Eterm db_format_dmc_err_info(Process *p, DMCErrInfo *ei);
+/* Formats an error info structure into a list of tuples. */
+void db_free_dmc_err_info(DMCErrInfo *ei);
+/* Completely free's an error info structure, including all recorded
+ errors */
+Eterm db_make_mp_binary(Process *p, Binary *mp, Eterm **hpp);
+/* Convert a match program to a erlang "magic" binary to be returned to userspace,
+ increments the reference counter. */
+int erts_db_is_compiled_ms(Eterm term);
+
+/*
+** Convenience when compiling into Binary structures
+*/
+#define IsMatchProgBinary(BP) \
+ (((BP)->flags & BIN_FLAG_MAGIC) \
+ && ERTS_MAGIC_BIN_DESTRUCTOR((BP)) == erts_db_match_prog_destructor)
+
+#define Binary2MatchProg(BP) \
+ (ASSERT_EXPR(IsMatchProgBinary((BP))), \
+ ((MatchProg *) ERTS_MAGIC_BIN_DATA((BP))))
+/*
+** Debugging
+*/
+#ifdef HARDDEBUG
+void db_check_tables(void); /* in db.c */
+#define CHECK_TABLES() db_check_tables()
+#else
+#define CHECK_TABLES()
+#endif
+
+#endif /* _DB_UTIL_H */