package jane.core;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
/**
* 存储引擎接口
* <p>
* 存储引擎的实现要保证一定的线程安全
*/
public interface Storage extends Closeable
{
/**
* 遍历数据库表的用户接口
* <p>
* 适用于key是非id类型的表
*/
interface WalkHandler<K>
{
/**
* 每次遍历一个记录都会调用此接口
* <p>
* 实现时要先对key加锁再调用getNoCache(推荐)或get获取记录value
* @param k 记录的key
* @return 返回true表示继续遍历, 返回false表示中断遍历
*/
boolean onWalk(K k) throws Exception;
}
/**
* 遍历数据库表的用户接口
* <p>
* 适用于key是id类型的表
*/
interface WalkHandlerLong
{
/**
* 每次遍历一个记录都会调用此接口
* <p>
* 实现时要先对key加锁再调用getNoCache(推荐)或get获取记录value
* @param k 记录的key
* @return 返回true表示继续遍历, 返回false表示中断遍历
*/
boolean onWalk(long k) throws Exception;
}
public static final class Helper
{
private Helper()
{
}
public static <K> boolean onWalkSafe(WalkHandler<K> handler, K k)
{
try
{
return handler.onWalk(k);
}
catch(Exception e)
{
Log.log.error("walk exception:", e);
return false;
}
}
public static boolean onWalkSafe(WalkHandlerLong handler, long k)
{
try
{
return handler.onWalk(k);
}
catch(Exception e)
{
Log.log.error("walk exception:", e);
return false;
}
}
}
interface Table<K, V extends Bean<V>>
{
/**
* 获取表ID
*/
int getTableId();
/**
* 获取表名
*/
String getTableName();
/**
* 根据记录的key获取value
*/
V get(K k);
/**
* 存储记录的key和value
* <p>
* 已存在key的记录会被覆盖<br>
* 目前的引擎实现不会出现并发的put和remove
*/
void put(K k, V v);
/**
* 根据记录的key删除记录
* <p>
* 目前的引擎实现不会出现并发的put和remove
*/
void remove(K k);
/**
* 按记录key的顺序遍历此表的所有记录
* <p>
* @param handler 遍历过程中返回false可中断遍历
* @param from 需要遍历的最小key. null表示最小值
* @param to 需要遍历的最大key. null表示最大值
* @param inclusive 遍历是否包含from和to的key
* @param reverse 是否按反序遍历
* @return 返回true表示已完全遍历, 返回false表示被用户中断
*/
boolean walk(WalkHandler<K> handler, K from, K to, boolean inclusive, boolean reverse);
}
interface TableLong<V extends Bean<V>>
{
/**
* 获取表ID
*/
int getTableId();
/**
* 获取表名
*/
String getTableName();
/**
* 根据记录的key获取value
*/
V get(long k);
/**
* 存储记录的key和value
* <p>
* 已存在key的记录会被覆盖<br>
* 目前的引擎实现不会出现并发的put和remove
*/
void put(long k, V v);
/**
* 根据记录的key删除记录
* <p>
* 目前的引擎实现不会出现并发的put和remove
*/
void remove(long k);
/**
* 获取计数器当前值,用于取得自增长ID
* <p>
* 目前的引擎实现不会出现并发的getCounter和setCounter
*/
long getIdCounter();
/**
* 设置计数器当前值,用于保存自增长ID
* <p>
* 目前的引擎实现不会出现并发的getCounter和setCounter
*/
void setIdCounter(long v);
/**
* 按记录key的顺序遍历此表的所有记录
* <p>
* @param handler 遍历过程中返回false可中断遍历
* @param from 需要遍历的最小key
* @param to 需要遍历的最大key
* @param inclusive 遍历是否包含from和to的key
* @param reverse 是否按反序遍历
* @return 返回true表示已完全遍历, 返回false表示被用户中断
*/
boolean walk(WalkHandlerLong handler, long from, long to, boolean inclusive, boolean reverse);
}
/**
* 打开数据库
* <p>
* 打开失败会抛出IOException或Error或RuntimeException异常
* @param file 数据库文件名. 所在目录必须已经存在,文件不存在时会自动创建新的数据库
*/
void openDB(File file) throws IOException;
/**
* 打开数据库表
* <p>
* 如果数据库表没有创建过,会自动创建新的<br>
* 表id和name可只使用其中一个来作为标识
* @param stubK 记录key的存根对象
* @param stubV 记录value的存根对象
*/
<K, V extends Bean<V>> Table<K, V> openTable(int tableId, String tableName, Object stubK, V stubV);
/**
* 打开key为ID类型的数据库表
* <p>
* ID类型即只能是>=0的long类型,可以为此而优化数据库的访问<br>
* 如果数据库表没有创建过,会自动创建新的<br>
* 表id和name可只使用其中一个来作为标识
* @param stubV 记录value的存根对象
*/
<V extends Bean<V>> TableLong<V> openTable(int tableId, String tableName, V stubV);
/**
* 准备批量写操作
* <p>
* 目前对存储引擎的操作是多线程读和单线程批量写和提交,读写操作可以并发<br>
* 此方法是在一轮批量写操作前调用的,和commit的调用成对出现,put调用只会出现在这两个调用之间
*/
void putBegin();
/**
* 刷新批量写操作
* <p>
* 调用这个函数后,之前批量的写操作要至少完成序列化,以保证之后对bean对象的写操作不会影响到此次提交数据库
* @param isLast 是否是最后一轮刷新,即在commit之前调用的
*/
void putFlush(boolean isLast);
/**
* 提交并刷新数据库
* <p>
* 把已写入数据库的数据完整地刷新到磁盘上
*/
void commit();
/**
* 关闭数据库
* <p>
* 要保证内存中的数据完整地刷新到磁盘上<br>
* 关闭后除了再执行openDB打开之外不会做任何其它操作
*/
@Override
void close();
/**
* 热备份数据库
* <p>
* 备份当前打开的数据库到新建的数据库中<br>
* 备份创建失败会抛出IOException或Error或RuntimeException异常
* @param file 备份目标的数据库文件名. 所在目录必须已经存在,文件已存在时会自动删除再执行备份
* @return 返回备份操作写入磁盘的字节数量. <0表示失败
*/
long backup(File file) throws IOException;
}