limax线程池与锁-Zdb

ZDB包括事物,锁,线程池等多个模块

1.zdb随着进程开启而启动

public final synchronized void start(limax.xmlgen.Zdb meta) {
    if (DBC.isRunning())
        throw new IllegalAccessError("DBC is in use.");
    this.meta = testMeta(meta);
    Set<String> unusedTables = MetaUtils.testAndTrySaveToDbAndReturnUnusedTables(meta);
    if (!isStartedOnce) {
        Runtime.getRuntime().addShutdownHook(new Thread(Zdb.this::stop, "limax.zdb.ShutdownHook"));
        isStartedOnce = true;
    }
    Trace.fatal("zdb start begin");
    mbeans = MBeans.register(MBeans.root(), this, "limax.zdb:type=Zdb,name=Zdb");
    try {
        //开启多种类型的线程池
        ConcurrentEnvironment env = ConcurrentEnvironment.getInstance();
        if (useFixedThreadPool) {
            env.newFixedThreadPool("limax.zdb.core", meta.getCorePoolSize());
            env.newFixedThreadPool("limax.zdb.procedure", meta.getProcPoolSize());
        } else {
            env.newThreadPool("limax.zdb.core", meta.getCorePoolSize());
            env.newThreadPool("limax.zdb.procedure", meta.getProcPoolSize());
        }
        scheduledExecutorService = env.newScheduledThreadPool("limax.zdb.scheduler", meta.getSchedPoolSize());
        coreExecutor = env.newTimeoutExecutor("limax.zdb.core", meta.getProcedure().getMaxExecutionTime(),
                TimeUnit.MILLISECONDS);
        lockEnvironment = new LockEnvironment(() -> meta.getDeadlockDetectPeriod());
        ScheduledThreadPoolExecutor checkpointScheduler = env.newScheduledThreadPool("limax.zdb.checkpoint", 1);
        procedureExecutors = new ConcurrentHashMap<>();
        //Lockeys管理锁
        Class.forName("limax.zdb.Lockeys");
        //Xbean,_Tables_ 初始化
        Class.forName("limax.zdb.XBean");
        tableClass = Class.forName("table._Tables_");
        Constructor<?> constructor = tableClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        table = constructor.newInstance();
        tables = new Tables();
        Field[] fields = tableClass.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);
        //初始化tables
        for (Field field : fields) {
            Object fieldValue = field.get(table);
            if (fieldValue instanceof AbstractTable)
                tables.add((AbstractTable) fieldValue);
        }
        tables.open(meta, unusedTables);
        tables.getLogger().dropTables(unusedTables.toArray(new String[unusedTables.size()]));
        //checkpoint初始化,用于数据定时刷新存储
        checkpoint = new Checkpoint(checkpointScheduler, tables);
        String trnHome = meta.getTrnHome();
        if (!trnHome.isEmpty()) {
            Path path = Paths.get(trnHome);
            Files.createDirectories(path);
            duration = new Duration(path, tables, () -> checkpoint.checkpoint(meta));
        }
        ManagementFactory.setCheckpointMBean(checkpoint);
        Trace.fatal("zdb start end");
        running = true;
    } catch (Throwable e) {
        Trace.fatal("Zdb start error", e);
        close();
        throw e instanceof XError ? (XError) e : new XError(e);
    }
}

2.Tables 持有所有表的引用(存储storages)

void open(limax.xmlgen.Zdb meta, Set<String> unusedTables) {
    if (null != logger)
        throw new XError("tables opened");
    switch (meta.getEngineType()) {
    case MYSQL:
        logger = new LoggerMysql(meta);
        break;
    case EDB:
        logger = new LoggerEdb(meta);
        break;
    }
    storages.add(tableSys.open(null, logger));
    tableSys.getAutoKeys().remove(unusedTables);
    Map<String, Integer> map = new HashMap<>();
    AtomicInteger idAlloc = new AtomicInteger();
    for (AbstractTable table : tables.values()) {
        StorageInterface storage = table.open(meta.getTable(table.getName()), logger);
        if (storage != null)
            storages.add(storage);
        TTable<?, ?> ttable = (TTable<?, ?>) table;
        ttable.setLockId(map.computeIfAbsent(ttable.getLockName(), k -> idAlloc.incrementAndGet()));
    }
    add(tableSys);
}

3.TStorage 引用edb和mysql两种存储引擎,是增删改查的中间层

private final StorageEngine engine;

TStorage(TTable<K, V> table, LoggerEngine logger) {
    this.table = table;
    switch (Zdb.meta().getEngineType()) {
    case MYSQL:
        engine = new StorageMysql((LoggerMysql) logger, table.getName());
        break;
    case EDB:
        engine = new StorageEdb((LoggerEdb) logger, table.getName());
        break;
    default:
        throw new XError("unknown engine type");
    }
}

增删改查

final boolean exist(K key, TTable<K, V> table) {
    Lock lock = snapshotLock.readLock();
    lock.lock();
    try {
        TRecord<K, V> r = snapshot.get(key);
        if (r != null)
            return r.exist();
    } finally {
        lock.unlock();
    }
    return engine.exist(table.marshalKey(key));
}

V find(K key, TTable<K, V> table) {
    OctetsStream value;
    Lock lock = snapshotLock.readLock();
    lock.lock();
    try {
        TRecord<K, V> r = snapshot.get(key);
        if (r != null) {
            value = r.find();
            if (value == null)
                return null;
        } else {
            value = null;
        }
    } finally {
        lock.unlock();
    }
    try {
        if (value == null) {
            Octets _value = engine.find(table.marshalKey(key));
            if (_value == null)
                return null;
            value = OctetsStream.wrap(_value);
        }
        return table.unmarshalValue(value);
    } catch (MarshalException e) {
        throw new RuntimeException(e);
    }
}

4.StorageEdb edb存储引擎

private final LoggerEdb edb;
private final String tableName;

public StorageEdb(LoggerEdb edb, String tableName) {
    this.edb = edb;
    this.tableName = tableName;
    try {
        this.edb.getDatabase().addTable(new String[] { tableName });
    } catch (Exception e) {
        throw new XError(e);
    }
}

@Override
public boolean exist(Octets key) {
    byte[] tkey = key.capacity() == key.size() ? key.array() : Arrays.copyOf(key.array(), key.size());
    try {
        //下面是edb表操作逻辑
        return edb.getDatabase().exist(tableName, tkey);
    } catch (Exception e) {
        throw new XError(e);
    }
}

5.TTable 数据表key-value上层操作封装,专注数据部分

public abstract class TTable<K, V> extends AbstractTable implements TTableMBean {
    private String lockname;
    private int lockId;
    private limax.xmlgen.Table meta;
    private AutoKeys.AutoKey autoKey;
    private Resource mbean;

    protected TTable() {
    }

    protected final Long nextKey() {
        return autoKey.next();
    }

    void recoverKey(long key) {
        autoKey.recover(key);
    }

    protected final boolean add(K key, V value) {
        Objects.requireNonNull(key, "key is null");
        Objects.requireNonNull(value, "value is null");
        Lockey lockey = Lockeys.getLockey(lockId, key);
        //包括在事务中
        Transaction.current().wAddLockey(lockey);
        if (null != autoKey)
            autoKey.accept((Long) key);
        countAdd.incrementAndGet();
        TRecord<K, V> r = cache.get(key);
        if (null != r)
            return r.add(value);
        countAddMiss.incrementAndGet();
        if (_exist(key)) {
            countAddStorageMiss.incrementAndGet();
            return false;
        }
        //将操作封装成一个TRecord
        cache.add(key, new TRecord<K, V>(this, value, lockey, TRecord.State.ADD));
        return true;
    }

    protected final boolean remove(K key) {
        Objects.requireNonNull(key, "key is null");
        Transaction current = Transaction.current();
        Lockey lockey = Lockeys.getLockey(lockId, key);
        current.wAddLockey(lockey);
        current.removeCachedTRecord(this, key);
        countRemove.incrementAndGet();
        TRecord<K, V> r = cache.get(key);
        if (null != r)
            return r.remove();
        countRemoveMiss.incrementAndGet();
        boolean exists = _exist(key);
        if (!exists)
            countRemoveStorageMiss.incrementAndGet();
        cache.add(key, new TRecord<K, V>(this, null, lockey, exists ? State.INDB_REMOVE : State.REMOVE));
        return exists;
    }
}

6.TRecord记录,zdb对表的操作都抽象成一条数据

final class TRecord<K, V> extends XBean {
    private final TTable<K, V> table;
    private final Lockey lockey;

    TRecord(TTable<K, V> table, V value, Lockey lockey, State state) {
        super(null, RECORD_VARNAME);
        this.table = table;
        if (null != value)
            Logs.link(value, this, RECORD_VARNAME, State.INDB_GET != state);
        this.value = value;
        this.lockey = lockey;
        this.state = state;
    }

    private void _remove() {
        Logs.link(value, null, null);
        Transaction.currentSavepoint().addIfAbsent(getLogKey(), new LogAddRemove());
        value = null;
    }

    boolean remove() {
        switch (state) {
        case INDB_GET:
            _remove();
            state = State.INDB_REMOVE;
            return true;
        case INDB_ADD:
            _remove();
            state = State.INDB_REMOVE;
            return true;
        case ADD:
            _remove();
            state = State.REMOVE;
            return true;
        default:
            return false;
        }
    }

    private void _add(V value) {
        Logs.link(value, this, RECORD_VARNAME);
        Transaction.currentSavepoint().addIfAbsent(getLogKey(), new LogAddRemove());
        this.value = value;
    }
}

7.Procedure 线程处理,线程被封装成ProcedureImpl

public ProcedureFuture(ProcedureImpl<P> p) {
    this(p, null);
}

private void launch() {
    this.future = Zdb.procedureExecutor(p.maxExecutionTime()).submit(this, p);
}

public ProcedureFuture(ProcedureImpl<P> p, Procedure.Done<P> done) {
    this.p = p;
    this.done = done;
    launch();
}

private void done() {
    if (done != null)
        try {
            done.doDone(p.process, p);
        } catch (Throwable e) {
            if (Trace.isErrorEnabled())
                Trace.error("doDone", e);
        }
}

ProcedureImpl

执行process方法

boolean call() {
    //事务环境
    int savepoint = Transaction.savepoint();
    try {
        //执行process方法,事务环境被Table.add,remove等操作处理
        if (process.process()) {
            setSuccess(true);
            setException(null);
            return true;
        }
    } catch (Exception e) {
        setException(e);
        Trace.log(Zdb.pmeta().getTrace(), "Procedure execute", e);
    }
    //失败时回滚
    Transaction.rollback(savepoint);
    setSuccess(false);
    return false;
}

private static boolean perform(ProcedureImpl<?> p) {
    try {
        Transaction.current().perform(p);
    } catch (XDeadlock e) {
        return false;
    } catch (Throwable e) {
    }
    return true;
}

static <P extends Procedure> Procedure.Result call(P p) {
    ProcedureImpl<P> impl = new ProcedureImpl<>(p);
    if (Transaction.current() == null) {
        try {
            Transaction.create();
            for (int retry = 0;;) {
                if (perform(impl))
                    break;
                retry++;
                if (retry > impl.retryTimes())
                    break;
                if (retry == impl.retryTimes() && impl.retrySerial())
                    impl.isolation = Transaction.Isolation.LEVEL3;
                try {
                    Thread.sleep(impl.delay());
                } catch (InterruptedException e) {
                }
            }
        } finally {
            Transaction.destroy();
        }
    } else {
        impl.call();
    }
    return impl;
}

8.表的操作引入锁和事务,再次分析TTable

protected final boolean add(K key, V value) {
    Objects.requireNonNull(key, "key is null");
    Objects.requireNonNull(value, "value is null");
    //当前事务中锁操作,不同表代表不同的锁
    Lockey lockey = Lockeys.getLockey(lockId, key);
    Transaction.current().wAddLockey(lockey);
    if (null != autoKey)
        autoKey.accept((Long) key);
    countAdd.incrementAndGet();
    //从缓存中取数据,缓存策略包括:TTableCacheConcurrentMap,TTableCacheLRU
    TRecord<K, V> r = cache.get(key);
    if (null != r)
        return r.add(value);
    countAddMiss.incrementAndGet();
    if (_exist(key)) {
        countAddStorageMiss.incrementAndGet();
        return false;
    }
    //将变化数据放入cache缓存,存入的是一条TRecord
    cache.add(key, new TRecord<K, V>(this, value, lockey, TRecord.State.ADD));
    return true;
}

9.缓存cache中变化表数据刷新 CheckPoint

synchronized void checkpoint(limax.xmlgen.Zdb meta) {
    if (Trace.isDebugEnabled())
        Trace.debug("---------------- begin ----------------");
    //表的存储引用
    final List<StorageInterface> storages = this.tables.getStorages();

    if (meta.getMarshalN() < 1)
        if (Trace.isWarnEnabled())
            Trace.warn("marshalN disabled");

    elapse.reset();
    for (int i = 1; i <= meta.getMarshalN(); ++i) {
        int countMarshalN = storages.stream().mapToInt(StorageInterface::marshalN).sum();
        this.marshalNCount += countMarshalN;
        if (Trace.isDebugEnabled())
            Trace.debug("marshalN=" + i + "/" + countMarshalN);
    }
    this.marshalNTotalTime += elapse.elapsed();
    Runnable cleanupDuration;
    {
        int countSnapshot;
        int countMarshal0;
        Lock lock = tables.flushWriteLock();
        lock.lock();
        elapse.reset();
        try {
            countMarshal0 = storages.stream().mapToInt(StorageInterface::marshal0).sum();
            countSnapshot = storages.stream().mapToInt(StorageInterface::snapshot).sum();
            cleanupDuration = Zdb.checkpointDuration();
        } finally {
            lock.unlock();
        }
        long snapshotTime = elapse.elapsedAndReset();
        if (snapshotTime / 1000000 > meta.getSnapshotFatalTime())
            Trace.fatal(
                    "snapshot time=" + snapshotTime + " snapshot=" + countSnapshot + " marshal0=" + countMarshal0);
        this.marshal0Count += countMarshal0;
        this.snapshotTotalTime += snapshotTime;
        this.snapshotCount += countSnapshot;
        if (Trace.isDebugEnabled())
            Trace.debug("snapshot=" + countSnapshot + " marshal0=" + countMarshal0);
    }
    int countFlush = storages.stream().mapToInt(StorageInterface::flush).sum();
    this.flushTotalTime += elapse.elapsedAndReset();
    if (Trace.isDebugEnabled())
        Trace.debug("flush=" + countFlush);
    if (countFlush > 0)
        this.tables.getLogger().checkpoint();
    if (countFlush > 0) {
        this.flushCount += countFlush;
        this.checkpointTotalTime += elapse.elapsedAndReset();
        if (Trace.isDebugEnabled())
            Trace.debug("checkpoint");
    }
    ++checkpointCount;
    if (cleanupDuration != null)
        cleanupDuration.run();
    if (Trace.isDebugEnabled())
        Trace.debug("----------------- end -----------------");
}

DataBase的flush,将数据存储到文本中

private synchronized void checkpoint(boolean rotate) {
    try {
        Collection<PageCache> tableCollection = tables.values();
        tableCollection.forEach(cache -> cache.writeFreeze());
        for (PageCache cache : tableCollection)
            cache.waitWriteFrozen();
        Map<PageCache, List<PageLayout>> snapshots = labeledHash.createSnapshots();
        tableCollection.forEach(cache -> {
            cache.setSnapshots(snapshots.get(cache));
            cache.writeUnfreeze();
        });
        if (!snapshots.isEmpty() || rotate) {
            logger.prepare(rotate);
            LabeledHash.releaseSnapshots(snapshots);
            logger.commit();
        }
        labeledHash.permitWash();
    } catch (IOException e) {
        Trace.fatal("limax.edb.checkpoint", e);
        System.exit(-1);
    }
}

10.总结

(1)缓存LRU策略,当内存表超过最大数量后悔主动删除

(2)Lockey hash锁调度,死锁是zdb经常出现的问题,对开发造成一定的难度

(3)procedure回滚是zdb优势

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值