package com.g414.haildb; import java.io.File; import java.nio.LongBuffer; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import com.g414.haildb.Transaction.TransactionLevel; import com.g414.haildb.impl.jna.HailDB; import com.sun.jna.Pointer; import com.sun.jna.ptr.PointerByReference; public class Database { public Database() { this(new DatabaseConfiguration()); } public Database(DatabaseConfiguration c) { Util.assertSuccess(HailDB.ib_init()); if (c.isAdaptiveHashEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("adaptive_hash_index")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("adaptive_hash_index")); } if (c.isAdaptiveFlushingEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("adaptive_flushing")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("adaptive_flushing")); } if (c.isDoublewriteEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("doublewrite")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("doublewrite")); } if (c.isFilePerTableEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("file_per_table")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("file_per_table")); } if (c.isPageChecksumsEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("checksums")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("checksums")); } if (c.isPrintVerboseLog()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("print_verbose_log")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("print_verbose_log")); } if (c.isRollbackOnTimeoutEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("rollback_on_timeout")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("rollback_on_timeout")); } if (c.isStatusFileEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("status_file")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("status_file")); } if (c.isSysMallocEnabled()) { Util.assertSuccess(HailDB.ib_cfg_set_bool_on("use_sys_malloc")); } else { Util.assertSuccess(HailDB.ib_cfg_set_bool_off("use_sys_malloc")); } Util.assertSuccess(HailDB.ib_cfg_set("data_file_path", c.getDatafilePath())); Util.assertSuccess(HailDB.ib_cfg_set("data_home_dir", c.getDataHomeDir())); Util.assertSuccess(HailDB.ib_cfg_set("log_group_home_dir", c.getLogFileHomeDirectory())); Util.assertSuccess(HailDB.ib_cfg_set("flush_log_at_trx_commit", c.getFlushLogAtTrxCommitMode().getCode())); Util.assertSuccess(HailDB.ib_cfg_set("flush_method", c.getFlushMethod().getCode())); Util.assertSuccess(HailDB.ib_cfg_set("force_recovery", c.getRecoveryMethod().getCode())); Util.assertSuccess(HailDB.ib_cfg_set("lru_block_access_recency", c.getLruBlockAccessRecency())); Util.assertSuccess(HailDB.ib_cfg_set("lru_old_blocks_pct", c.getLruOldBlocksPct())); Util.assertSuccess(HailDB.ib_cfg_set("max_dirty_pages_pct", c.getMaxDirtyPagesPct())); Util.assertSuccess(HailDB.ib_cfg_set("max_purge_lag", c.getMaxPurgeLagSeconds())); Util.assertSuccess(HailDB.ib_cfg_set("open_files", c.getOpenFilesLimit())); Util.assertSuccess(HailDB.ib_cfg_set("autoextend_increment", c.getAutoextendIncrementSizePages())); Util.assertSuccess(HailDB.ib_cfg_set("io_capacity", c.getIoCapacityIOPS())); Util.assertSuccess(HailDB.ib_cfg_set("sync_spin_loops", c.getSyncSpinLoops())); Util.assertSuccess(HailDB.ib_cfg_set("lock_wait_timeout", c.getLockWaitTimeoutSeconds())); if (c.getLogFileSize() > 0) { Util.assertSuccess(HailDB.ib_cfg_set("log_file_size", c.getLogFileSize())); } if (c.getLogBufferSize() > 0) { Util.assertSuccess(HailDB.ib_cfg_set("log_buffer_size", c.getLogBufferSize())); } if (c.getLogFilesInGroup() > 0) { Util.assertSuccess(HailDB.ib_cfg_set("log_files_in_group", c.getLogFilesInGroup())); } if (c.getBufferPoolSize() > 0) { Util.assertSuccess(HailDB.ib_cfg_set("buffer_pool_size", c.getBufferPoolSize())); } if (c.getAdditionalMemPoolSize() > 0) { Util.assertSuccess(HailDB.ib_cfg_set("additional_mem_pool_size", c.getAdditionalMemPoolSize())); } // Util.assertSuccess(HailDB.ib_cfg_set("log_file_size", c.getLogFileSize())); // Util.assertSuccess(HailDB.ib_cfg_set("log_buffer_size", c.getLogBufferSize())); // Util.assertSuccess(HailDB.ib_cfg_set("log_files_in_group", c.getLogFilesInGroup())); // Util.assertSuccess(HailDB.ib_cfg_set("buffer_pool_size", c.getBufferPoolSize())); // Util.assertSuccess(HailDB.ib_cfg_set("additional_mem_pool_size", c.getAdditionalMemPoolSize())); Util.assertSuccess(HailDB.ib_startup(c.getFileFormat().getCode())); isOpenning.set(true); Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { public void run() { Database.this.shutdown(false); } })); } public void createDatabase(String databaseName) { Util.assertSchemaOperationSuccess(HailDB.ib_database_create(databaseName)); } public void dropDatabase(String databaseName) { File dbFile = new File(databaseName); if (!dbFile.exists()) { return; } Util.assertSuccess(HailDB.ib_database_drop(databaseName)); } public Transaction beginTransaction(TransactionLevel level) { Pointer trx = HailDB.ib_trx_begin(level.getCode()); return new Transaction(trx); } public void createTable(TableDef tableDef) { this.createTable(tableDef, TableType.DYNAMIC, 0); } public void createTable(TableDef tableDef, TableType type, int pageSize) { if (tableExists(tableDef)) { throw new InnoException("table already exists: " + tableDef.getName()); } PointerByReference schema = new PointerByReference(); Util.assertSuccess(HailDB.ib_table_schema_create(tableDef.getName(), schema, type.getCode(), pageSize)); for (ColumnDef def : tableDef.getColumnDefs().values()) { int attr = 0; for (ColumnAttribute a : def.getAttrs()) { attr |= a.getCode(); } if (!def.getType().equals(ColumnType.BLOB)) { Util.assertSuccess(HailDB.ib_table_schema_add_col(schema.getValue(), def.getName(), def.getType().getCode(), attr, (short) 0, def.getLength().intValue())); } else { Util.assertSuccess(HailDB.ib_table_schema_add_col(schema.getValue(), def.getName(), def.getType().getCode(), 0, (short) 0, 0)); } } for (Map.Entry<String, IndexDef> entry : tableDef.getIndexDefs().entrySet()) { PointerByReference index = new PointerByReference(); Util.assertSuccess(HailDB.ib_table_schema_add_index(schema.getValue(), entry.getKey(), index)); IndexDef part = entry.getValue(); Map<String, Integer> prefixLenOverrides = part.getPrefixLenOverrides(); for (ColumnDef col : part.getColumns()) { int prefixLenOverride = prefixLenOverrides.containsKey(col.getName()) ? prefixLenOverrides.get(col.getName()) : 0; Util.assertSuccess(HailDB.ib_index_schema_add_col(index.getValue(), col.getName(), prefixLenOverride)); } if (part.isClustered()) { Util.assertSuccess(HailDB.ib_index_schema_set_clustered(index.getValue())); } else if (part.isUnique()) { Util.assertSuccess(HailDB.ib_index_schema_set_unique(index.getValue())); } } LongBuffer tableId = LongBuffer.allocate(1); Transaction trx = this.beginTransaction(TransactionLevel.REPEATABLE_READ); try { Util.assertSuccess(HailDB.ib_schema_lock_exclusive(trx.getTrx())); Util.assertSuccess(HailDB.ib_table_create(trx.getTrx(), schema.getValue(), tableId)); trx.commit(); } catch (InnoException e) { trx.rollback(); throw e; } finally { HailDB.ib_table_schema_delete(schema.getValue()); } } public void dropTable(TableDef def) { Transaction trx = this.beginTransaction(TransactionLevel.REPEATABLE_READ); try { Util.assertSuccess(HailDB.ib_schema_lock_exclusive(trx.getTrx())); Util.assertSuccess(HailDB.ib_table_drop(trx.getTrx(), def.getName())); trx.commit(); } catch (InnoException e) { throw e; } } public Long truncateTable(TableDef tableDef) { LongBuffer tableId = LongBuffer.allocate(1); Util.assertSuccess(HailDB.ib_table_truncate(tableDef.getName(), tableId)); return tableId.get(); } public boolean tableExists(TableDef tableDef) { boolean found = false; Transaction txn = null; Cursor check = null; try { txn = this.beginTransaction(TransactionLevel.REPEATABLE_READ); check = txn.openTable(tableDef); found = true; } catch (InnoException expected) { if (!expected.getMessage().contains("Table not found")) { throw expected; } } finally { if (check != null) { check.close(); } if (txn != null) { txn.commit(); } } return found; } public void shutdown(boolean fast) { if(isOpenning.compareAndSet(true, false)){ int flag = fast ? HailDB.ib_shutdown_t.IB_SHUTDOWN_NO_BUFPOOL_FLUSH : HailDB.ib_shutdown_t.IB_SHUTDOWN_NORMAL; Util.assertSuccess(HailDB.ib_shutdown(flag)); } } private volatile AtomicBoolean isOpenning = new AtomicBoolean(false); }