📄 parsev3pmdatafile.java
字号:
/**
* @(#)FileInfo.java Nov 23, 2006 4:51:40 PM
*
* COPYRIGHT DaTang Mobile Communications Equipment CO.,LTD
*/
package com.datangmobile.oss.omc.pc.v3file;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import com.datangmobile.oss.omc.common.exception.DatabaseException;
import com.datangmobile.oss.omc.common.nea.pm.pmdata.DefaultPmDataInput;
import com.datangmobile.oss.omc.common.nea.pm.pmdata.PmUtil;
import com.datangmobile.oss.omc.common.nea.pm.pmdata.TableConfig;
import com.datangmobile.oss.omc.common.server.pm.dto.GuideLineData;
import com.datangmobile.oss.omc.common.server.pm.dto.NameValue;
import com.datangmobile.oss.omc.common.server.pm.exception.FileParseException;
import com.datangmobile.oss.omc.pc.ConnectDB;
import com.datangmobile.oss.omc.pc.DeleteFileQueue;
import com.datangmobile.oss.omc.pc.IInsertDataIntoLatecyTable;
import com.datangmobile.oss.omc.pc.InsertDataIntoLatecyTable;
import com.datangmobile.oss.omc.pc.ParseFileExceptionQueue;
import com.datangmobile.oss.omc.pc.PmConst;
import com.datangmobile.oss.omc.pc.util.CounterGroupService;
import com.datangmobile.oss.omc.pc.util.DBConnectionException;
import com.datangmobile.oss.omc.pc.util.Database;
import com.datangmobile.oss.omc.pc.util.FileInfo;
import com.datangmobile.oss.omc.pc.util.IimUtil;
import com.datangmobile.oss.omc.pc.util.MsgInputStream;
import com.datangmobile.oss.omc.pc.util.NeMoi;
import com.datangmobile.oss.platform.util.ILogger;
import com.datangmobile.oss.platform.util.ModuleLogger;
/**
* V3性能文件解析
*
* 主要是解决GuideLineData入库时产生的"碎片记录". 所谓碎片记录是指本来一条数据库记录可以存储的数据,分成了多条记录.
* 碎片记录会严重影响数据库的查询效率. 该类主要应用的技术如下 1)虚拟GuideLineData
* 虚拟GuideLineData有多条相关的(在同一表且同一记录的)实际GuideLineData组成. 所以取10000为强制插入的经验值.
* 如果该值,可能会导致内存溢出,太小则数据库会产生很多碎片记录. 2)对象池
*
* 处于效率和空间平衡,不可能完全避免碎片记录
*
* @author xingyong
* @version 1.0
*
*/
public class ParseV3PMDataFile {
/**
* 连接对象
*/
private Connection conn = null;
private static final ILogger log = ModuleLogger.getPmLogger()
.getOperLogger();
// 因为conn会自动关闭,所以用保持数据库连接无效
private static boolean useDBConnectonPool = false;
// 由于不能保持数据库连接,用对象池几乎没有意义
private static boolean useObjectPool = true;
/**
* 用于缓存文件解析对象
*/
private static List<ParseV3PMDataFile> v3FileParserObjectPool = new ArrayList<ParseV3PMDataFile>();
/**
* 用于缓存以数据库表记录为导向的GuideLine记录
*/
private Map<String, List<GuideLineData>> recordOrientedMap = new HashMap<String, List<GuideLineData>>();
/**
* 用于缓存数据库连接的preparedstatement
*/
private Map<String, PreparedStatement> preparedStatementMap = new HashMap<String, PreparedStatement>();
// 用于指示该实例是不是忙
private boolean busy = true;
// 用于标识如何批量处理的条数
private int batchCounter = 0;
/**
* 缺省的开始时间,因为同一个文件时间信息99.9%都是一样的,这样可以节省GuideLineData存储空间
*/
private Date defaultBeginTime;
/**
* 缺省的开始时间,因为同一个文件时间信息99.9%都是一样的,这样可以节省GuideLineData存储空间
*/
private Date defaultEndTime;
/**
* 用于记录同一dn的计数器是不是保存到同一的表,如果不一样那么表名计数器记录可以入库了
*/
private Map<String, String> tableAndDnMap = new HashMap<String, String>();
/**
* 初始化插入计数器延迟表的类
*/
private IInsertDataIntoLatecyTable insertLatecyInfo = new InsertDataIntoLatecyTable();
/**
* 该V2性能数据文件中V3计数器组的集合
*/
private Map<Integer, Set<Date>> v3CounterGroupMap = new HashMap<Integer, Set<Date>>();
// private static Map<String,String> sqlMap =
// Collections.synchronizedMap(new HashMap<String, String>());
/**
* 查找一个空闲的文件解析实例. 返回实例前应该置busy为true
*
* @param fileInfo
* @return 如果有异常则返回NULL
*/
public static synchronized ParseV3PMDataFile findIdleV3FileParser(
FileInfo fileInfo) {
if (v3FileParserObjectPool.size() > 16) {
log.warn(ParseV3PMDataFile.class, "目前缓存V3性能文件解析实例数目过大,现在数目为:"
+ v3FileParserObjectPool.size());
log.warn(ParseV3PMDataFile.class, "清除解析实例");
v3FileParserObjectPool.clear();
}
for (ParseV3PMDataFile fileParser : v3FileParserObjectPool) {
if (fileParser.isBusy())
continue;
else {
if (fileParser.init(fileInfo)) {
fileParser.setBusy(true);
log.debug(ParseV3PMDataFile.class, "复用以前的V3性能文件解析实例");
return fileParser;
} else
return null;
}
}
ParseV3PMDataFile fileParser = null;
try {
fileParser = new ParseV3PMDataFile(fileInfo);
fileParser.setBusy(true);
} catch (Exception e) {
return null;
}
return fileParser;
}
/**
* 用于获取解析文件实例
*
* @param fileInfo
* @return
*/
public static ParseV3PMDataFile getV3FileParser(FileInfo fileInfo) {
ParseV3PMDataFile fileParser = null;
try {
fileParser = new ParseV3PMDataFile(fileInfo);
// fileParser.setBusy(true);
} catch (Exception e) {
return null;
}
return fileParser;
}
/**
* 构造器
*/
private ParseV3PMDataFile(FileInfo fileInfo) throws Exception {
// 初始化
if (!init(fileInfo)) {
throw new Exception("初始化V3性能文件解析错误");
}
if (useObjectPool)
v3FileParserObjectPool.add(this);
}
/**
* 初始化
*
* @throws SQLException
* @throws IOException
* @throws DBConnectionException
*/
private boolean init(FileInfo fileInfo) {
try {
/**
* 加入连接数据库的部分 设置提交模式为不是自动提交模式
*/
if (conn == null || conn.isClosed()) {
conn = Database.connect();
conn.setAutoCommit(false);
preparedStatementMap.clear();
// log.debug(this.getClass(), "为V3性能文件解析创建数据库连接");
} else {
// 复用以前的连接
log.debug(this.getClass(), "复用以前的数据库连接及相关PreparedStatement");
}
return true;
} catch (Exception ex) {
log.error("数据库不能连接", ex);
// 重新将文件放入队列中,等待解析
reputParseQueue(fileInfo, FileInfo.DB_EXCEPTION);
// 将数据库的状态置为不可用
ConnectDB.getInstance().setConnectSuccess(false);
return false;
}
}
/**
* 用于统一处理时间信息的保存,如果和缺省的时间不一样,就设置到GuideLineData实例里,如果一样就免了
*
* @param data
* @param endTimeSetInV3Group
*/
private void readTimeInfo(MsgInputStream msgInStream,
GuideLineData guideLineData, Set<Date> endTimeSetInV3Group) {
/*
* 开始时间 modify by liuyuan 2007-4-9 根据o接口读取的为UINT32 用java中的long型保存
* BUGCN00015626
*
* modify by liuyuan 2008-6-11 CNBUG00019010 OMC负责把秒数归0
*/
Date beginTime = PmUtil.getWholeDate(new Date(
msgInStream.readUInt() * 1000), Calendar.SECOND);
/*
* 结束时间 modify by liuyuan 2007-4-9 根据o接口读取的为UINT32 用java中的long型保存
* BUGCN00015626
*/
Date endTime = PmUtil.getWholeDate(new Date(
msgInStream.readUInt() * 1000), Calendar.SECOND);
if (defaultBeginTime == null) {
defaultBeginTime = beginTime;
}
if (defaultEndTime == null) {
defaultEndTime = endTime;
}
if (!beginTime.equals(defaultBeginTime))
guideLineData.setBegin(beginTime);
if (!endTime.equals(defaultEndTime))
guideLineData.setEnd(endTime);
endTimeSetInV3Group.add(endTime);
}
/**
* 解析文件
*
* @param file
* 文件
* @param type
* 上传文件的网元类型
* @throws FileNotFoundException
* @throws IOException
* @throws SQLException
* @throws InterruptedException
* @throws SQLException
* @throws IOException
*/
public void parseFileAndInsertDB(FileInfo fileinfo) {
long beginTestTime = System.currentTimeMillis();
busy = true;
int error = 32;
// 对整个解析过程都需要捕捉异常
FileInputStream filein = null;
DataInputStream datain = null;
File file = fileinfo.getFile();
String type = fileinfo.getNeType();
String fileName = file.getName();
String[] splitNames = fileName.split("_");
// 从文件名中获取rnc的ID号
int rncId = 0;
try {
// 名字形如:pm_rnc_0010_20080819_0400.dat(4.00.00)
// rncId = Integer.valueOf(splitNames[2], 16);
// 名字形如:pm1218990600_rnc_0012.dat(3.40.300)
String rncSt = splitNames[2].replace('.', '_');
rncId = Integer.valueOf(rncSt.split("_")[0], 16);
} catch (Exception ex) {
log.error("文件名不合规范,不能取到RNC的ID号。fileName: " + file.getName(), ex);
File f = new File(PmConst.PM_DIR + File.separator + file.getName()
+ ".bad");
boolean save = file.renameTo(f);
if (save) {
log.error(ParseV3PMDataFile.class, "保存文件为 " + f.getName()
+ " 成功");
} else {
log.error(ParseV3PMDataFile.class, "保存文件为 " + f.getName()
+ " 失败");
}
return;
}
/*
* 记录每个记录的字节个数 用来判断是否已经到了一条记录的结束
*/
int count = 0;
int dataCount = 0;
int insertCount = 0;
try {
filein = new FileInputStream(file);
datain = new DataInputStream(filein);
log.info(ParseV3PMDataFile.class, "Ready to parse file:"
+ file.getAbsoluteFile() + " File type:" + type + " rncId:"
+ rncId);
// long begin = System.currentTimeMillis();
/* 跳过头部 */
datain.skipBytes(32);
// count = count + 32;
while (datain.available() > 0) {
// 本条记录的字节个数
int lRecordLen = datain.readInt();
// count = count + 4;
byte[] body = new byte[lRecordLen];
// log.debug(ParseV3DataFile.class, " read byte[] use time begin
// " +
// System.currentTimeMillis());
datain.read(body);
// log.debug(ParseV3DataFile.class, " read byte[] use time end "
// +
// System.currentTimeMillis());
MsgInputStream msgInStream = new MsgInputStream(body);
msgInStream.skipBytes(14);
count = count + 14;
// 计数器组ID
int groupId = msgInStream.readShort();
count = count + 2;
ArrayList<String> names = null;
try {
names = CounterGroupService.getInstance().getCounterNames(
groupId);
} catch (Exception e) {
log
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -