package com.jackson.db.service;
import com.jackson.db.SqlUtil;
import com.jackson.db.dao.UrlDao;
import com.jackson.db.po.Url;
import com.jackson.executor.DBSingleExecutor;
import com.jackson.utils.ListUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.URL;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Created by Jackson on 2016/11/4.
*/
public class UrlService implements IDaoService<Url> {
private static Logger logger = LogManager.getLogger(UrlService.class.getName());
private final SqlSessionFactory factory;
private LinkedBlockingQueue<Url> queue;
private final HashSet<Url> updateCompleteUrsSet;
private final HashSet<Url> insertUrsSet;
private final LinkedList<Url> insertUrsList;
private LinkedList<Url> updateCompleteUrsList;
private final String tableName;
private int minUrlCatch = 10;
private int getUrlSize = 100;
/**
*
* @param tableName 表名
*/
public UrlService(String tableName) {
this.tableName = tableName;
queue = new LinkedBlockingQueue<>();
factory = SqlUtil.getFactory();
updateCompleteUrsSet = new HashSet<>();
updateCompleteUrsList = new LinkedList<>();
insertUrsSet = new HashSet<>();
insertUrsList = new LinkedList<>();
init();
}
public UrlService setMinUrlCatch(int minUrlCatch) {
this.minUrlCatch = minUrlCatch;
return this;
}
/**
* 每次从数据库获取url的条数
* @param getUrlSize
* @return
*/
public UrlService setGetUrlSize(int getUrlSize) {
this.getUrlSize = getUrlSize;
return this;
}
public void insert(List<Url> urls){
if(ListUtil.isEmpty(urls))return;
synchronized(insertUrsSet){
if(queue.size()==0){
Url url = urls.remove(urls.size() - 1);
queue.offer(url);
}
insertUrsSet.addAll(urls);
DBSingleExecutor.instance.execute(new InsertTask());
}
}
public void insert(Url url){
synchronized(insertUrsSet){
if(queue.size()==0){
url.setState(Url.STATE_TAKE_OUT);
queue.offer(url);
}
insertUrsSet.add(url);
DBSingleExecutor.instance.execute(new InsertTask());
}
}
private void insertUrl2Database(List<Url> urls) {
logger.info("插入url到数据库 urlSize:{}", urls.size());
SqlSession sqlSession = null;
try {
sqlSession = factory.openSession();
UrlDao mapper = sqlSession.getMapper(UrlDao.class);
mapper.insertUrls(tableName,urls);
sqlSession.commit();
} catch (Exception e) {
logger.error(e.toString());
}finally {
if (sqlSession != null)
sqlSession.close();
}
}
public Url take() {
logger.info("queue size:{}", queue.size());
if (queue.size() < minUrlCatch) {
synchronized (this){
if(queue.size()<minUrlCatch){
//databaseToQueue();
DBSingleExecutor.instance.execute(new Database2QueueTask());
}
}
}
Url temp = null;
try {
temp = queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return temp;
}
//task线程执行
protected void insertUrlsToDatabase(){
synchronized (insertUrsSet){
if(insertUrsSet.size()>0){
insertUrsList.addAll(insertUrsSet);
insertUrl2Database(insertUrsList);
insertUrsSet.clear();//存入数据库方法成功后才会清空
insertUrsList.clear();//存入数据库方法成功后才会清空
}
}
}
//task线程执行
protected void completeUrlsToDatabase(){
synchronized (updateCompleteUrsSet){
if(updateCompleteUrsSet.size()>0){
updateCompleteUrsList.addAll(updateCompleteUrsSet);
completeUrlsToDatabase(updateCompleteUrsList);
updateCompleteUrsSet.clear();//存入数据库方法成功后才会清空
updateCompleteUrsList.clear();
}
}
}
private void completeUrlsToDatabase(List<Url> completeUrls) {
SqlSession sqlSession = null;
try {
sqlSession = factory.openSession(ExecutorType.BATCH);
UrlDao mapper = sqlSession.getMapper(UrlDao.class);
logger.info("完成的url存入数据库completeUrls size:{}", completeUrls.size());
mapper.updateUrlsToComplete(tableName,completeUrls);
sqlSession.commit();
} catch (Exception e) {
logger.error(e.toString());
}finally {
sqlSession.close();
}
}
private void databaseToQueue() {
if(queue.size()>minUrlCatch)return;
SqlSession sqlSession = null;
try {
sqlSession = factory.openSession();
UrlDao mapper = sqlSession.getMapper(UrlDao.class);
List<Url> urls = mapper.findUrls(tableName,getUrlSize);
logger.info("从数据库获取 urls size:{}", urls.size());
if (urls.size() > 0) {
queue.addAll(urls);
mapper.updateUrlsToTakenOut(tableName,urls);
sqlSession.commit();
}
logger.info("addAfter queue size:{}", queue.size());
} catch (Exception e) {
logger.error(e.toString());
}finally {
if (sqlSession != null)
sqlSession.close();
}
}
public void completeUrl(Url url) {
url.setState(Url.STATE_COMPLETE);
synchronized (updateCompleteUrsSet){
updateCompleteUrsSet.add(url);
DBSingleExecutor.instance.execute(new CompleteTask());
}
logger.info("设置完成状态 updateCompleteUrsSet size:{} url:{}", updateCompleteUrsSet.size(),url.getUrl());
}
/**
* 放入queue,等待被取出
* @param url
*/
public void add(Url url) {
logger.info("放入内存queue中 url is {}",url);
queue.offer(url);
}
/**
* 放入queue,等待被取出
* @param urls
*/
public void add(List<Url> urls) {
logger.info("放入内存queue中 url size {}",urls.size());
queue.addAll(urls);
}
/**
* 将上次取出但是没执行的,变成free状态
*/
private void init(){
createTable();
setTakeState2Free();
}
private void setTakeState2Free(){
SqlSession sqlSession = null;
try {
sqlSession = factory.openSession();
UrlDao mapper = sqlSession.getMapper(UrlDao.class);
mapper.setTakeState2Free(tableName);
sqlSession.commit();
} catch (Exception e){
logger.error(e.toString());
} finally{
sqlSession.close();
}
}
private void createTable(){
SqlSession sqlSession = null;
try {
sqlSession = factory.openSession();
UrlDao mapper = sqlSession.getMapper(UrlDao.class);
mapper.createTable(tableName);
sqlSession.commit();
} catch (Exception e){
logger.error(e.toString());
} finally{
sqlSession.close();
}
}
private class InsertTask extends DBSingleExecutor.DBTask{
@Override
public void run() {
insertUrlsToDatabase();
}
}
private class CompleteTask extends DBSingleExecutor.DBTask{
@Override
public void run() {
completeUrlsToDatabase();
}
}
private class Database2QueueTask extends DBSingleExecutor.DBTask{
@Override
public void run() {
databaseToQueue();
}
}
}