This commit is contained in:
y
2016-04-23 15:01:52 +08:00
commit 62902dd37c
235 changed files with 9260 additions and 0 deletions

26
.classpath Normal file
View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/lib/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/lib/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/lib/classes"/>
</classpath>

29
.project Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>middleware-mom</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7

View File

@@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

2
broker.sh Normal file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env bash
java -cp target/lib/middleware-mom-1.0.jar com.alibaba.middleware.race.mom.Broker

2
build.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env bash
mvn clean package

107
pom.xml Normal file
View File

@@ -0,0 +1,107 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.alibaba.race</groupId>
<artifactId>middleware-mom</artifactId>
<packaging>jar</packaging>
<name>middleware-mom</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<directory>${basedir}/target/lib</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/java/assembly.xml</descriptor>
</descriptors>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- this is used for inheritance merges -->
<phase>package</phase>
<!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>2.34</version>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.23.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<version>1.0</version>
</project>

View File

@@ -0,0 +1,30 @@
<assembly>
<id>bin</id>
<baseDirectory>middleware-mom</baseDirectory>
<includeBaseDirectory>true</includeBaseDirectory>
<formats>
<format>dir</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>README*</include>
<include>LICENSE*</include>
<include>NOTICE*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/lib</directory>
<outputDirectory>lib</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -0,0 +1,276 @@
package com.alibaba.middleware.race.mom;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.broker.function.MessageManager;
import com.alibaba.middleware.race.mom.broker.function.MessageSend;
import com.alibaba.middleware.race.mom.broker.group.ConsumerGroup;
import com.alibaba.middleware.race.mom.serializer.RpcDecoder;
import com.alibaba.middleware.race.mom.serializer.RpcEncoder;
import com.alibaba.middleware.race.mom.util.InfoBodyConsumer;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
public class Broker {
private static Logger logger = LoggerFactory.getLogger(Broker.class);
/**
* 启动broker之前的netty服务器处理
* @param port
* @throws Exception
*/
public void bind(int port) throws Exception {
//启动消费进度定时任务
// storeSubscribe(true, 5000);
// scanSendInfotMap();
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()*3);
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_BACKLOG, 1024*1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
//
// .option(ChannelOption.SO_BACKLOG, 1024)
// //
// .option(ChannelOption.SO_REUSEADDR, true)
// //
// .option(ChannelOption.SO_KEEPALIVE, false)
// //
// .childOption(ChannelOption.TCP_NODELAY, true)
// .option(ChannelOption.SO_SNDBUF, 65535)
// //
// .option(ChannelOption.SO_RCVBUF, 65535)
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new RpcDecoder()).addLast(new RpcEncoder())
.addLast(new SimpleChannelInboundHandler<Object>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object info) throws Exception {
if (InfoBodyConsumer.class.isInstance(info)) {
// 接受消费者订阅处理
processConsumer((InfoBodyConsumer) info, ctx);
} else if (ConsumeResult.class.isInstance(info)) {
// 收到消费者ConsumeResult
logger.debug(" 收到消费者ConsumeResult");
ConsumerGroup.confirmConsumer((ConsumeResult)info, ctx);
// confirmConsumer((ConsumeResult) info, ctx);
}else if(MessageSend.class.isInstance(info)){
//System.out.println("收到消息");
MessageManager.recieveMsg((MessageSend) info,ctx);
// MessageManager.recieveMsg((LinkedBlockingQueue)info,ctx);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.error("broker 异常:");
// logger.error(cause.getMessage());
cause.printStackTrace();
ctx.close();
}
});
}
});//
ChannelFuture future = serverBootstrap.bind(port).sync();
logger.debug("mom服务启动成功...... 绑定端口" + port);
// 等待服务端监听端口关闭
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
logger.error("smom服务抛出异常 " + e.getMessage());
} finally {
// 优雅退出 释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
logger.debug("mom服务优雅的释放了线程资源...");
}
}
/**
* 收到消费者的订阅关系,并创建队列
* @param consumerRequestInfo
* @param ctx
*/
public void processConsumer(InfoBodyConsumer consumerRequestInfo, final ChannelHandlerContext ctx) {
String topic = consumerRequestInfo.getTopic();
String groupid = consumerRequestInfo.getGroupId();
Map<String, String> filter = consumerRequestInfo.getFilterMap();
TopicAndFilter topicAndFilter = new TopicAndFilter(topic, filter);
Channel consumer = ctx.channel();
logger.error("消费者:" + consumer.hashCode()+"发起订阅"+consumerRequestInfo);
ConsumerGroup.addConsumer(consumer,groupid,topicAndFilter);
//
}
// public void scanSendInfotMap(){
// this.timoutScannerTimer.schedule(new TimerTask(){
// @Override
// public void run() {
// for(Map.Entry<String , SendInfo> entry:msgManager.getSendInfoMap().entrySet()){
// SendInfo sendInfo=entry.getValue();
// for(Map.Entry<ConsumerGroup , SendStatus> groupstatus:sendInfo.getGroup2status().entrySet()){
// if(groupstatus.getValue()==SendStatus.TIMEOUT||sendInfo.isTimeout(System.currentTimeMillis())){
// String msgId=sendInfo.getMsgId();
// final String topic=sendInfo.getTopic();
// final TopicAndFilter topicAndfilter=sendInfo.getTopicAndFilter();
// final ConsumerGroup group=groupstatus.getKey();
// BlockingQueue<String> reSendMessageQueue=topicAndgroup2reSendMsgQueue.get(topic+ "@" +group);
// if(reSendMessageQueue==null){
// reSendMessageQueue=new LinkedBlockingQueue<String>();
// reSendMessageQueue.add(msgId);
// topicAndgroup2reSendMsgQueue.put(topic+ "@" +group,reSendMessageQueue);
// }else {
// reSendMessageQueue.add(msgId);
// }
// // messageCache.remove(msgId);//消息进入重试队列这里应该移除了sendResultMap还可以重试结果使用
// reSendPool.execute(new Runnable(){
// @Override
// public void run() {
// reSendToConsumer(topicAndgroup2reSendMsgQueue.get(topic+ "@" +group),group);
// }
// });
// // if(msgid2offset.containsKey(msgId)){
// // topicAndgroup2subScribe.get(topic+"@"+group).get(sendInfo.getQueueId()).setCurrentoffset(msgid2offset.get(msgId));
// // msgid2offset.remove(msgId);
// // }
// }
// }
// }
//
// }
// },timeoutLimit+100,1000);
// }
/**
* 恢复订阅关系
*/
// public void recover(){
// logger.debug("恢复订阅关系队列");
// long startTime = System.currentTimeMillis();
// ArrayList<Offset>offsets =substore.read();
// System.out.println("offsets:"+offsets);
// String topic;
// String group;
// String queueId;
// String topicAndFilter;
// for(Offset offset:offsets){
// topic=offset.getTopicId();
// topicAndFilter=offset.getTopicAndFilter();
// group=offset.getGroupId();
// queueId=offset.getQueueId();
// //恢复topicAndgroup2subScribe
// LinkedList<Offset> offsetList;
// if(!topicAndgroup2subScribe.containsKey(topic+"@"+group))
// {
// offsetList=new LinkedList<Offset>();
// topicAndgroup2subScribe.put(topic+"@"+group, offsetList);
// }else
// {
// offsetList=topicAndgroup2subScribe.get(topic+"@"+group);
// }
// offsetList.add(Integer.parseInt(queueId),offset);
// //恢复topicAndgroup2sendMsgQueue
// LinkedList<BlockingQueue<Integer>> sendQueuesList;
// if(!topicAndgroup2sendMsgQueue.containsKey(topic + "@" + group))
// {
// sendQueuesList=new LinkedList<BlockingQueue<Integer>>();
// topicAndgroup2sendMsgQueue.put(topic + "@" + group, sendQueuesList);
// }else
// {
// sendQueuesList=topicAndgroup2sendMsgQueue.get(topic + "@" + group);
// }
// BlockingQueue<Integer>sendQueue=new LinkedBlockingQueue<>();
// sendQueuesList.add(Integer.parseInt(queueId),sendQueue);
// //消息入队(这里只磁盘拉)
// int currentOffset=offset.getCurrentoffset();
// Message msg;
// int i=0;//currentOffset偏移量
// List<byte[]> blist = mstore.readByteNormal(topicAndFilter,"t","t",queueId+"",offset.getCurrentoffset()+1, offset.getCacheOffset()-1);
// System.out.println(blist.size());
// for(byte[] b:blist){
// try{
// msg=(Message)fst.asObject(b);
// }catch(Exception e){
// continue;
// }
// System.out.println(msg);
// sendQueue.add(msg.getOffset());
// msgManager.getMessageCacheMap().put(msg.getOffset(), msg);
// msgid2offset.put(msg.getMsgId(), currentOffset+i);
// i++;
// }
//
// }
//
// long endTime = System.currentTimeMillis();
// System.out.println("恢复cost" + (endTime - startTime));
// }
/**
* 仅更新到磁盘 Subscribe之前的 offset,这部分属于 离散重试(至少中间有一条成功) ,须重试offset表存储到磁盘,broker故障重启只能离散随机恢复消息
* 如果存在Subscribe之后的 offset,必然发生连续>=1(甚至大量)超时,连续超时将随Subscribe存储到磁盘,broker故障重启将发生连续一片(>=1条)消息恢复
* @param start
* @param during
*/
public void storeResendOffset(boolean start,long during/*ms*/){
}
/**
* 定时任务-存储订阅关系
* @param start
* @param during
*/
// public void storeSubscribe(boolean start,long during/*ms*/)
// {
// if(start==false)
// return;
// logger.debug("异步-订阅关系/消费进度定时持久化任务");
//
// shceduledPool.scheduleWithFixedDelay(
// new Runnable() {
// @Override
// public void run() {
// ArrayList<Offset> sublist=new ArrayList<>();
// logger.error("遍历订阅关系:"+topicAndgroup2subScribe.size());
// for (Map.Entry<String/* topic@group */, LinkedList<Offset>> entry : topicAndgroup2subScribe.entrySet())
// {
// //System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
// sublist.addAll(entry.getValue());
// }
// substore.write(sublist);
// logger.error("订阅关系刷盘");
// }
// },
// 5000,
// during,
// TimeUnit.MILLISECONDS);
// }
public static void main(String[] args) throws Exception {
int port = 9999;
Broker broker=new Broker();
// Recover recover=new Recover();
// recover.recover();
// SubsStore.subscribeStoreStart();
broker.bind(port);
}
}

View File

@@ -0,0 +1,49 @@
package com.alibaba.middleware.race.mom;
import java.io.Serializable;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
public class ConsumeResult implements Serializable {
private static final long serialVersionUID = -4489150726886715441L;
private ConsumeStatus status=ConsumeStatus.FAIL;
private String info;
private String msgId;
//来自哪个订阅集群
private String groupId;
//来自哪 些 订阅集群组
private TopicAndFilter topicAndFilter;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public TopicAndFilter getTopicAndFilter() {
return topicAndFilter;
}
public void setTopicAndFilter(TopicAndFilter topicAndFilter) {
this.topicAndFilter = topicAndFilter;
}
public void setStatus(ConsumeStatus status) {
this.status = status;
}
public ConsumeStatus getStatus() {
return status;
}
public void setInfo(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
}

View File

@@ -0,0 +1,6 @@
package com.alibaba.middleware.race.mom;
public enum ConsumeStatus {
SUCCESS,
FAIL
}

View File

@@ -0,0 +1,56 @@
package com.alibaba.middleware.race.mom;
import java.util.Map;
import com.alibaba.middleware.race.mom.util.InfoBodyConsumer;
public interface Consumer {
/**
* 启动消费者,初始化底层资源。要在属性设置和订阅操作发起之后执行
*/
void start();
/**
* 发起订阅操作
*
* @param topic
* 只接受该topic的消息
* @param filter
* 属性过滤条件,例如 area=hz表示只接受area属性为hz的消息。消息的过滤要在服务端进行
* @param listener
*/
void subscribe(String topic, String filter, MessageListener listener);
/**
* 设置消费者组idbroker通过这个id来识别消费者机器
*
* @param groupId
*/
void setGroupId(String groupId);
/**
* 停止消费者broker不再投递消息给此消费者机器。
*/
void stop();
void prepare();
String getGroupId();
Map<String, String> getFilterMap();
void setFilterMap(Map<String, String> filterMap);
Message getMsg();
void setMsg(Message msg);
InfoBodyConsumer getConsumerRequestInfo();
void setConsumerRequestInfo(InfoBodyConsumer consumerRequestInfo);
String getTopic();
void setTopic(String topic);
}

View File

@@ -0,0 +1,270 @@
package com.alibaba.middleware.race.mom;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.nustaq.serialization.FSTConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.serializer.RpcDecoder;
import com.alibaba.middleware.race.mom.serializer.RpcEncoder;
import com.alibaba.middleware.race.mom.util.InfoBodyConsumer;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
public class DefaultConsumer implements Consumer, Serializable {
private static final long serialVersionUID = -4454001515077708258L;
private static Logger logger = LoggerFactory.getLogger(DefaultConsumer.class);
private String groupId;
private Map<String, String> filterMap;
transient private ChannelFuture future;
transient private NioEventLoopGroup group;
transient private String SIP;
private Message msg;
private InfoBodyConsumer consumerRequestInfo;
private MessageListener listener;
private String topic;
FSTConfiguration fst=FSTConfiguration.getDefaultConfiguration();
Bootstrap bootstrap;
boolean reconnect=false;
@Override
public void start() {
prepare();
}
@Override
public void prepare() {
SIP=System.getProperty("SIP");
if(SIP==null)
SIP="127.0.0.1";
System.out.println("consumer connect:"+System.getProperty("SIP"));
group = new NioEventLoopGroup();
try {
bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.SO_REUSEADDR, true).option(ChannelOption.SO_KEEPALIVE, true)
// .option(ChannelOption.TCP_NODELAY, true)
// //
// .option(ChannelOption.SO_KEEPALIVE, false)
// //
// .option(ChannelOption.SO_SNDBUF, 65535)
// //
// .option(ChannelOption.SO_RCVBUF,65535)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new RpcEncoder())
.addLast(new RpcDecoder())
.addLast(new SimpleChannelInboundHandler<Object>() {
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
connect();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable e)
throws Exception {
logger.error("消费者异常关闭:");
e.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(final ChannelHandlerContext ctx, Object info)
throws Exception {
logger.debug("client receive msg");
Message msg =(Message)info;
//返回ACK
final ConsumeResult consumeResult=listener.onMessage(msg);
//设置谁的 ack
consumeResult.setMsgId(msg.getMsgId());
/*
*设置 consumeResult来源
*/
consumeResult.setGroupId(groupId);
consumeResult.setTopicAndFilter(new TopicAndFilter(topic,filterMap));
// if(Math.random()>0.95){
// new Thread(new Runnable(){
//
// @Override
// public void run() {
// // TODO Auto-generated method stub
// try {
// Thread.sleep(10000);
//
// ctx.writeAndFlush(consumeResult);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
//
// }).start();;
// }else
ctx.writeAndFlush(consumeResult);
}
});
}
});
connect();
} catch (InterruptedException e) {
logger.error("消费者抛出异常 " + e.getMessage());
}
}
public void connect() throws InterruptedException
{
try{
future = bootstrap.connect(SIP, 9999).sync();
future.channel().writeAndFlush(consumerRequestInfo);
logger.error("连接成功");
}catch(Exception e)
{
// Thread.sleep(1000);
logger.error("重新连接");
connect();
}
}
@Override
public void subscribe(String topic, String filter, MessageListener listener) {
this.topic=topic;
this.listener = listener;
if (null != filter && (!"".equals(filter))) {
filterMap = new HashMap<String, String>();
String[] temp = filter.split("=",2);
filterMap.put(temp[0],temp[1]);
this.setFilterMap(filterMap);
/*for(int i=0;i<temp.length;i++){
filterMap.put(temp[i], temp[++i]);
}*/
}
consumerRequestInfo = new InfoBodyConsumer();
consumerRequestInfo.setFilterMap(filterMap);
consumerRequestInfo.setTopic(topic);
consumerRequestInfo.setGroupId(groupId);
}
@Override
public void setGroupId(String groupId) {
this.groupId = groupId;
}
@Override
public String getGroupId() {
return groupId;
}
@Override
public Map<String, String> getFilterMap() {
return filterMap;
}
@Override
public void setFilterMap(Map<String, String> filterMap) {
this.filterMap = filterMap;
}
@Override
public Message getMsg() {
return msg;
}
@Override
public void setMsg(Message msg) {
this.msg = msg;
}
@Override
public InfoBodyConsumer getConsumerRequestInfo() {
return consumerRequestInfo;
}
@Override
public void setConsumerRequestInfo(InfoBodyConsumer consumerRequestInfo) {
this.consumerRequestInfo = consumerRequestInfo;
}
@Override
public String getTopic() {
return topic;
}
@Override
public void setTopic(String topic) {
this.topic = topic;
}
@Override
public void stop() {
future.channel().closeFuture();
future.channel().close();
group.shutdownGracefully();
logger.debug("消费者的释放了线程资源...");
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((filterMap == null) ? 0 : filterMap.hashCode());
result = prime * result + ((groupId == null) ? 0 : groupId.hashCode());
result = prime * result + ((topic == null) ? 0 : topic.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DefaultConsumer other = (DefaultConsumer) obj;
if (filterMap == null) {
if (other.filterMap != null)
return false;
} else if (!filterMap.equals(other.filterMap))
return false;
if (groupId == null) {
if (other.groupId != null)
return false;
} else if (!groupId.equals(other.groupId))
return false;
if (topic == null) {
if (other.topic != null)
return false;
} else if (!topic.equals(other.topic))
return false;
return true;
}
}

View File

@@ -0,0 +1,328 @@
package com.alibaba.middleware.race.mom;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.broker.function.MessageSend;
import com.alibaba.middleware.race.mom.serializer.RpcEncoder;
public class DefaultProducer implements Producer {
transient private static Logger logger = LoggerFactory.getLogger(DefaultProducer.class);
private String topic;
private String groupId;
private static String producerId="pro_"+String.valueOf(Math.random()*100);
private ChannelFuture future;
private static Random random=new Random();
private NioEventLoopGroup group;
private String SIP;
private SendCallback callback;
private ExecutorService sendPool = Executors.newFixedThreadPool(1);
private BlockingQueue<Message> sendQueue=new LinkedBlockingQueue<Message>();
private Map<String,BlockingQueue<SendResult>> resultMap=new ConcurrentHashMap<String, BlockingQueue<SendResult>>();
private Bootstrap bootstrap;
boolean isGroupMsg=false;
private AtomicLong msgIdProduce=new AtomicLong();
private CountDownLatch sendWait=new CountDownLatch(1);
private Object lock=new Object();
private Map<String,SendCallback> asyncResults=new HashMap<>();
public DefaultProducer() {
}
@Override
public void asyncSendMessage(Message message, SendCallback callback) {
Message msg = buildMessage(message, callback,1);
//加入同步等待队列
logger.debug("生产者准备发起请求和消息");
// resultMap.put(message.getMsgId(), new LinkedBlockingQueue<SendResult>(1));
asyncResults.put(msg.getMsgId(),callback);
MessageSend msgSend=new MessageSend();
msgSend.getSendIds().add(msg.getMsgId());
future.channel().writeAndFlush(msgSend);
}
private AtomicInteger msgCount=new AtomicInteger();
@Override
public SendResult sendMessage(Message message) {
int msgCountL=msgCount.incrementAndGet();
Message msg = buildMessage(message, null,"ackGroup", msgCountL);
resultMap.put(message.getMsgId(), new LinkedBlockingQueue<SendResult>(1));
sendQueue.add(msg);
if(msgCountL>199){
sendWait.countDown();
}
SendResult sr=null;
try {
sr = resultMap.get(message.getMsgId()).poll(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(sr==null)
{
sr=new SendResult();
sr.setStatus(SendStatus.FAIL);
}
// synchronized(lock){
// try {
// lock.wait();
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
return sr;
}
/**
* 对Message 进行必要的信息设置,测试设置了groupId和topic producer.setGroupId(PID+code);producer.setTopic(topic);
* @param msg
* @param callback
* @return
*/
private Message buildMessage (Message msg, SendCallback callback,int count) {
if (callback != null) {
this.callback = callback;
logger.debug("生产者异步发送消息");
}
msg.setMsgId(String.valueOf(Math.random())+" "+String.valueOf(count));
msg.setTopic(topic);
msg.setBornTime(System.currentTimeMillis());
return msg;
}
private Message buildMessage (Message msg, SendCallback callback,String qianzhui,int count) {
if (callback != null) {
this.callback = callback;
logger.debug("生产者异步发送消息");
}
//msg.setMsgId(qianzhui+" "+String.valueOf(count));
msg.setMsgId(String.valueOf((int)(Math.random()*999%999))+" "+String.valueOf(count));
msg.setTopic(topic);
msg.setBornTime(System.currentTimeMillis());
return msg;
}
@Override
public void start() {
SIP=System.getProperty("SIP");
if(SIP==null)
SIP="127.0.0.1";
System.out.println("connect:"+System.getProperty("SIP"));
group = new NioEventLoopGroup();
bootstrap = new Bootstrap();
bootstrap.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.SO_REUSEADDR, true).option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
// //
.option(ChannelOption.SO_KEEPALIVE,true)
// //
// .option(ChannelOption.SO_SNDBUF, 65535)
////// //
// .option(ChannelOption.SO_RCVBUF,65535)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
.addLast(new RpcEncoder())
.addLast(new LineBasedFrameDecoder(1024*256))
.addLast(new StringDecoder())
.addLast(new SimpleChannelInboundHandler<Object>() {
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
logger.error("producer失去broker链接");
connect();
}
@Override
protected void channelRead0(ChannelHandlerContext arg0, Object info) throws Exception {
logger.debug("recv ack "+(String)info);
if(info!=null/*&&info.toString().startsWith("ackGroup"*/){
String id[]=((String)info).split("@");
//System.out.println("收到:"+info.toString());
//System.out.println(id.length+":len:"+id[0]+" | "+id[1]);
if(id[0].startsWith("fail"))
{
//System.out.println("无人订阅");
SendResult sr=new SendResult();
sr.setMsgId(id[1]);
resultMap.get(id[1]).put(sr);
}else
{
for(int i=1;i<id.length;i++)
{
//System.out.println(id[i]);
SendResult sr=new SendResult();
sr.setMsgId(id[i]);
resultMap.get(id[i]).put(sr);
}
}
// synchronized(lock){
// lock.notifyAll();
// }
} else {
// 异步方式接受数据
if(asyncResults.containsKey((String)info)){
SendResult sr=new SendResult();
sr.setMsgId((String)info);
asyncResults.get((String)info).onResult(sr);;
}else{
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
logger.error("--生产者的异常关闭--" + cause.getMessage());
cause.printStackTrace();
logger.error("重新连接");
ctx.close();
connect();
}
});
}
});
connect();
}
/**
* 连接
*
*/
public void connect() {
try {
future = bootstrap.connect(SIP, 9999).sync();
logger.error("连接成功");
// TODO Auto-generated catch block
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.error("重新连接");
connect();
}
/*
* 添加发送任务
*/
sendPool.execute(new Runnable(){
@Override
public void run() {
while(true){
long start=System.currentTimeMillis();
// messageGroup=false;
// AtomicInteger waitTime=new AtomicInteger();
/**
* 这部分待完善现在为了测tps先不管系统的真实可用性了
*/
try {
sendWait.await(30,TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* 创建本次祖发对象同时产生borntime
*/
MessageSend msgSend=new MessageSend();
while(true){
logger.debug("start make messageGroup");
Message msg=null;
msg = sendQueue.poll();
// if(!isGroupMsg&&msg==null){
// break;
// }
if (msg==null&&msgSend.getBodys().size()>199){
break;
}else if (msg==null&&msgSend.getBodys().size()==1){
try {//很有可能只有一条消息,比如函数测试,再确认一下
msg = sendQueue.poll(10,TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(msg==null){
logger.error("10ms no message produced after last first message");
break;
}
}else if(msg==null){
continue;
}
if(msgSend.getTopic()==null||msgSend.getProperties()==null){
msgSend.setProperties(msg.getProperties());
msgSend.setTopic(msg.getTopic());
}
msgSend.getBodys().add(msg.getBody());
msgSend.getSendIds().add(msg.getMsgId());
}
if(msgSend.getBodys().size()>0){
//msgSend.setSendId("ackGroup "+String.valueOf(msgSend.getBodys().size()));
// logger.error((System.currentTimeMillis()-start)+"后生产者一次打包发送"+msgSend.getBodys().size());
future.channel().writeAndFlush(msgSend);
msgCount.set(0);
sendWait=new CountDownLatch(1);
}
}
}
});
}
@Override
public void stop() {
future.channel().closeFuture();
future.channel().close();
group.shutdownGracefully();
sendPool.shutdown();
}
@Override
public void setGroupId(String groupId) {
// TODO Auto-generated method stub
this.groupId = groupId;
}
@Override
public void setSIP(String sip) {
this.SIP = sip;
}
@Override
public void setTopic(String topic) {
this.topic = topic;
}
}

View File

@@ -0,0 +1,233 @@
//package com.alibaba.middleware.race.mom;
//
//import io.netty.bootstrap.Bootstrap;
//import io.netty.channel.ChannelFuture;
//import io.netty.channel.ChannelHandlerContext;
//import io.netty.channel.ChannelInitializer;
//import io.netty.channel.ChannelOption;
//import io.netty.channel.SimpleChannelInboundHandler;
//import io.netty.channel.nio.NioEventLoopGroup;
//import io.netty.channel.socket.SocketChannel;
//import io.netty.channel.socket.nio.NioSocketChannel;
//import io.netty.handler.codec.LineBasedFrameDecoder;
//import io.netty.handler.codec.string.StringDecoder;
//
//import java.util.ArrayList;
//import java.util.Map;
//import java.util.concurrent.BlockingQueue;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.LinkedBlockingQueue;
//import java.util.concurrent.TimeUnit;
//import java.util.concurrent.atomic.AtomicLong;
//
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import com.alibaba.middleware.race.mom.serializer.RpcEncoder;
//import com.alibaba.middleware.race.mom.util.InfoBodyProduceList;
//
//
//public class DefaultProducer1 implements Producer {
// transient private static Logger logger = LoggerFactory.getLogger(DefaultProducer.class);
// private String topic;
// private String groupId;
// private static String producerId="pro_"+String.valueOf(Math.random()*100);
// private ChannelFuture future;
// private NioEventLoopGroup group;
// private String SIP;
// Object obj=new Object();
// private SendCallback callback;
// private SendResult sr;
// private Map<String,BlockingQueue<SendResult>> resultMap=new ConcurrentHashMap<String, BlockingQueue<SendResult>>();
// private BlockingQueue<MessageInfo> sendQueue= new LinkedBlockingQueue<MessageInfo>(100);
// private ExecutorService sendPool = Executors.newFixedThreadPool(1);
// private Bootstrap bootstrap;
// public DefaultProducer1() {startSend();}
//
// @Override
// public void asyncSendMessage(Message message, SendCallback callback) {
// MessageInfo msgInfo = buildMessage(message, callback);
// //加入同步等待队列
// logger.debug("生产者准备发起请求和消息");
// resultMap.put(message.getMsgId(), new LinkedBlockingQueue<SendResult>(1));
// future.channel().writeAndFlush(msgInfo);
// }
// /**
// * 对Message 进行必要的信息设置,测试设置了groupId和topic producer.setGroupId(PID+code);producer.setTopic(topic);
// * @param msg
// * @param callback
// * @return
// */
// private MessageInfo buildMessage (Message msg, SendCallback callback) {
// if (callback != null) {
// this.callback = callback;
// logger.debug("生产者异步发送消息");
// }
//
// msg.setTopic(topic);
// msg.setBornTime(System.currentTimeMillis());
// msg.makeID();
// return new MessageInfo(msg,producerId,this.groupId);
// }
//
// @Override
// public SendResult sendMessage(Message message) {
// MessageInfo msgInfo = buildMessage(message, null);
// while(!sendQueue.offer(e)){
//
// }
//
// if(sendQueue.put(msgInfo);(msgInfo)){
// sendQueue.size()
// }else {
//
// new MessageInfoQueue(sendQueue,);
// sendQueue=new LinkedBlockingQueue<MessageInfo>(100);
// }
//
// synchronized(obj){
// try {
// obj.wait();
// } catch (InterruptedException e) {
// }
//// resultMap.put(message.getMsgId(), new LinkedBlockingQueue<SendResult>(1));
//// SendResult sr=null;
//// try {
//// sr=resultMap.get(message.getMsgId()).take();
//// } catch (InterruptedException e) {
//// sr=new SendResult();
//// sr.setStatus(SendStatus.FAIL);
//// }
//
// return sr;}
// }
//
// public void buildQueue(){
// MessageInfoQueue msgInfoQueue=new MessageInfoQueue();
// while(!sendQueue.isEmpty()){
// sendQueue.
// msgInfoQueue.
// }
// Message msg=sendQueue.poll();
//
//
//
//
// }
//
//
// @Override
// public void setGroupId(String groupId) {
// // TODO Auto-generated method stub
// this.groupId = groupId;
// }
//
// @Override
// public void setSIP(String sip) {
// this.SIP = sip;
// }
//
// @Override
// public void setTopic(String topic) {
// this.topic = topic;
// }
// public void startSend(){
// sendPool.execute(new Runnable(){
//
// @Override
// public void run() {
// while(true){
// System.out.println(sendQueue.size());
// if(sendQueue.size()==200){
// future.channel().writeAndFlush(sendQueue);
// sendQueue.clear();
// }
// }
// }
//
// });
// }
// @Override
// public void start() {
//// try {
//// Thread.sleep(500);
//// } catch (InterruptedException e1) {
//// e1.printStackTrace();
//// }
// SIP=System.getProperty("SIP");
// if(SIP==null)
// SIP="127.0.0.1";
// System.out.println("connect:"+System.getProperty("SIP"));
// group = new NioEventLoopGroup();
// try {
// bootstrap = new Bootstrap();
// bootstrap.group(group).channel(NioSocketChannel.class)
// .option(ChannelOption.SO_REUSEADDR, true).option(ChannelOption.SO_KEEPALIVE, true)
// .handler(new ChannelInitializer<SocketChannel>() {
// @Override
// public void initChannel(SocketChannel channel) throws Exception {
// channel.pipeline()
// .addLast(new RpcEncoder())
// .addLast(new LineBasedFrameDecoder(1024))
// .addLast(new StringDecoder())
// .addLast(new SimpleChannelInboundHandler<Object>() {
//
// @Override
// public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// logger.error("producer失去broker链接");
// connect();
// }
// @Override
// protected void channelRead0(ChannelHandlerContext arg0, Object info) throws Exception {
// // main work;
// String msgId=info.toString();
// sr=new SendResult();
// sr.setMsgId(msgId);
// synchronized(obj){
//// DefaultProducer.this.sr=sr;
// obj.notifyAll();
//// obj.notify();
// }
//// if (null == callback) {
//// resultMap.get(msgId).add(sr);
//// return;
//// } else {
//// // 异步方式接受数据
//// callback.onResult(sr);
//// }
// }
// @Override
// public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
//
// logger.error("--生产者的异常关闭--" + cause.getMessage());
// cause.printStackTrace();
// ctx.close();
// }
// });
// }
// });
// connect();
// } catch (InterruptedException e) {
// logger.error("producer 抛出异常 " + e.getMessage());
// }
// }
// public void connect() throws InterruptedException
// {
// try{
// future = bootstrap.connect(SIP, 9999).sync();
// logger.error("连接成功");
// }catch(Exception e)
// {
// Thread.sleep(1000);
// logger.error("重新连接");
// connect();
// }
// }
// @Override
// public void stop() {
// group.shutdownGracefully();
// }
//
//}

View File

@@ -0,0 +1,191 @@
//package com.alibaba.middleware.race.mom;
//
//import io.netty.bootstrap.Bootstrap;
//import io.netty.channel.ChannelFuture;
//import io.netty.channel.ChannelHandlerContext;
//import io.netty.channel.ChannelInitializer;
//import io.netty.channel.ChannelOption;
//import io.netty.channel.SimpleChannelInboundHandler;
//import io.netty.channel.nio.NioEventLoopGroup;
//import io.netty.channel.socket.SocketChannel;
//import io.netty.channel.socket.nio.NioSocketChannel;
//import io.netty.handler.codec.LineBasedFrameDecoder;
//import io.netty.handler.codec.string.StringDecoder;
//
//import java.util.ArrayList;
//import java.util.Map;
//import java.util.concurrent.BlockingQueue;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.LinkedBlockingQueue;
//import java.util.concurrent.TimeUnit;
//import java.util.concurrent.atomic.AtomicLong;
//
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
//import com.alibaba.middleware.race.mom.serializer.RpcEncoder;
//import com.alibaba.middleware.race.mom.util.InfoBodyProduceList;
//
//
//public class DefaultProducer2 implements Producer {
// transient private static Logger logger = LoggerFactory.getLogger(DefaultProducer.class);
// private String topic;
// private String groupId;
// private static String producerId="pro_"+String.valueOf(Math.random()*100);
// private ChannelFuture future;
// private NioEventLoopGroup group;
// private String SIP;
// private SendCallback callback;
// private Map<String,BlockingQueue<SendResult>> resultMap=new ConcurrentHashMap<String, BlockingQueue<SendResult>>();
// private Bootstrap bootstrap;
// Object obj=new Object();
// private SendResult sendResult;
// public DefaultProducer2() {}
//
// @Override
// public void asyncSendMessage(Message message, SendCallback callback) {
// MessageInfo msgInfo = buildMessage(message, callback);
// //加入同步等待队列
// logger.debug("生产者准备发起请求和消息");
// resultMap.put(message.getMsgId(), new LinkedBlockingQueue<SendResult>(1));
// future.channel().writeAndFlush(msgInfo);
// }
// /**
// * 对Message 进行必要的信息设置,测试设置了groupId和topic producer.setGroupId(PID+code);producer.setTopic(topic);
// * @param msg
// * @param callback
// * @return
// */
// private MessageInfo buildMessage (Message msg, SendCallback callback) {
// if (callback != null) {
// this.callback = callback;
// logger.debug("生产者异步发送消息");
// }
//
// msg.setTopic(topic);
// msg.setBornTime(System.currentTimeMillis());
// msg.makeID();
// return new MessageInfo(msg,producerId,this.groupId);
// }
//
// @Override
// public SendResult sendMessage(Message message) {
// MessageInfo msgInfo = buildMessage(message, null);
// //resultMap.put(msg.getMsgId(), new LinkedBlockingQueue<SendResult>(1));
// future.channel().writeAndFlush(msgInfo);
// //SendResult sr=null;
// synchronized(obj){
// try {
// obj.wait();
// } catch (InterruptedException e) {
// }
// }
//// try {
//// sr=resultMap.get(msg.getMsgId()).take();
//// } catch (InterruptedException e) {
//// sr=new SendResult();
//// sr.setStatus(SendStatus.FAIL);
//// }
// return sendResult;
// }
//
// @Override
// public void setGroupId(String groupId) {
// // TODO Auto-generated method stub
// this.groupId = groupId;
// }
//
// @Override
// public void setSIP(String sip) {
// this.SIP = sip;
// }
//
// @Override
// public void setTopic(String topic) {
// this.topic = topic;
// }
//
// @Override
// public void start() {
//// try {
//// Thread.sleep(500);
//// } catch (InterruptedException e1) {
//// e1.printStackTrace();
//// }
// SIP=System.getProperty("SIP");
// if(SIP==null)
// SIP="127.0.0.1";
// System.out.println("connect:"+System.getProperty("SIP"));
// group = new NioEventLoopGroup();
// try {
// bootstrap = new Bootstrap();
// bootstrap.group(group).channel(NioSocketChannel.class)
// .option(ChannelOption.SO_REUSEADDR, true).option(ChannelOption.SO_KEEPALIVE, true)
// .handler(new ChannelInitializer<SocketChannel>() {
// @Override
// public void initChannel(SocketChannel channel) throws Exception {
// channel.pipeline()
// .addLast(new RpcEncoder())
// .addLast(new LineBasedFrameDecoder(1024))
// .addLast(new StringDecoder())
// .addLast(new SimpleChannelInboundHandler<Object>() {
//
// @Override
// public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// logger.error("producer失去broker链接");
// connect();
// }
// @Override
// protected void channelRead0(ChannelHandlerContext arg0, Object info) throws Exception {
// // main work;
// String msgId=info.toString();
// SendResult sr=new SendResult();
// sendResult=sr;
// sr.setMsgId(msgId);
// if (null == callback) {
// synchronized(obj){
//// DefaultProducer.this.sr=sr;
//// obj.notifyAll();
// obj.notify();
// }
// //resultMap.get(result).put(sr);
// } else {
// // 异步方式接受数据
// callback.onResult(sr);
// }
// }
// @Override
// public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
//
// logger.error("--生产者的异常关闭--" + cause.getMessage());
// cause.printStackTrace();
// ctx.close();
// }
// });
// }
// });
// connect();
// } catch (InterruptedException e) {
// logger.error("producer 抛出异常 " + e.getMessage());
// }
// }
// public void connect() throws InterruptedException
// {
// try{
// future = bootstrap.connect(SIP, 9999).sync();
// logger.error("连接成功");
// }catch(Exception e)
// {
// Thread.sleep(1000);
// logger.error("重新连接");
// connect();
// }
// }
// @Override
// public void stop() {
// group.shutdownGracefully();
// }
//
//}

View File

@@ -0,0 +1,82 @@
package com.alibaba.middleware.race.mom;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* Message ,目前只需要 三个属性,用于消费者消费(可能有遗漏,根据消费者消费即可)
* @author youngforever
*/
public class Message implements Serializable{
private static final long serialVersionUID = 1982349723732590L;
private transient static AtomicLong msgIdProduce=new AtomicLong();
/**
* 测试严证,消费等需要的必要字段
*/
private String msgId;
private String topic;
private byte[] body;
private Map<String, String> properties = new HashMap<String, String>();
private long bornTime;
// public void makeID(){
// if(msgId==null){
// msgId=this.topic+this.properties.toString()+"_"+String.valueOf(msgIdProduce.incrementAndGet());
// }
// }
public String getTopic() {
return topic;
}
public Message(){}
public Message( String topic, byte[] body,
Map<String, String> properties, long bornTime) {
this.topic = topic;
this.body = body;
this.properties = properties;
this.bornTime = bornTime;
}
public void setTopic(String topic) {
this.topic = topic;
}
public byte[] getBody() {
return body;
}
public void setBody(byte[] body) {
this.body = body;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public void setProperty(String key,String property){
this.properties.put(key, property);
}
public String getProperty(String key){
return this.properties.get(key);
}
public long getBornTime() {
return bornTime;
}
public void setBornTime(long bornTime) {
this.bornTime = bornTime;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public String toString(){
return this.msgId;
}
}

View File

@@ -0,0 +1,11 @@
package com.alibaba.middleware.race.mom;
public interface MessageListener {
/**
*
* @param message
* @return
*/
ConsumeResult onMessage(Message message);
}

View File

@@ -0,0 +1,20 @@
package com.alibaba.middleware.race.mom;
public interface Producer {
void setSIP(String sip);
void start();
void setTopic(String topic);
void setGroupId(String groupId);
SendResult sendMessage(Message message);
void asyncSendMessage(Message message, SendCallback callback);
void stop();
}

View File

@@ -0,0 +1,6 @@
package com.alibaba.middleware.race.mom;
public class QueueMessage extends Message{
private byte[] body;
private long bornTime;
}

View File

@@ -0,0 +1,5 @@
package com.alibaba.middleware.race.mom;
public interface SendCallback {
void onResult(SendResult result);
}

View File

@@ -0,0 +1,36 @@
package com.alibaba.middleware.race.mom;
import java.io.Serializable;
public class SendResult implements Serializable {
/**
*
*/
private static final long serialVersionUID = 321275686710864167L;
private String info;
private SendStatus status=SendStatus.SUCCESS;
private String msgId;
public String getInfo() {
return info;
}
public String getMsgId() {
return msgId;
}
public SendStatus getStatus() {
return status;
}
public void setInfo(String info) {
this.info = info;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public void setStatus(SendStatus status) {
this.status = status;
}
@Override
public String toString(){
return "msg "+msgId+" send "+(status==SendStatus.SUCCESS?"success":"fail")+" info:"+info;
}
}

View File

@@ -0,0 +1,30 @@
package com.alibaba.middleware.race.mom;
/**
* 发送状态
*
*/
public enum SendStatus{
SUCCESS,
FAIL,
TIMEOUT/*收到ack超时*/,
/**
* 投递中
*/
SEND,
/**
* 重投中
*/
RESEND,
/**
* 消费失败重投
*/
FAILRESEND,
/**
* 超时重投
*/
TIMEOUTRESEND,
/**
* 订阅集群所有消费者不在线
*/
GROUPLOST
}

View File

@@ -0,0 +1,32 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.util.Timer;
import java.util.TimerTask;
import com.alibaba.middleware.race.mom.config.Config;
/**
* 消息堆积处理,当内存消息堆积过多,将不再内存中缓存消息,堆积减少后从硬盘拉取消息
* 如果有大量超时消费者集群和正常快速消费集群,大量超时消息将不堆积内存,从磁盘拉取,保证不影响正常集群的消费tps
* @author young
*
*/
public class AccumulateHandler {
public static volatile boolean full =false;
private static Timer memoryCheckTimer=new Timer();
/**
* 是否可以继续内存添加消息
* @param memoryCacheMaxOffset
* @return
*/
public static void startCheckMemory(){
memoryCheckTimer.schedule(new TimerTask(){
@Override
public void run() {
if((double)Runtime.getRuntime().freeMemory()/Runtime.getRuntime().totalMemory()<(1-Config.memoryFullFactor)){//可用内存小于虚拟机内存3/4时不能再往内存堆积消息
full=true;
}
}
},5000,5000);
}
}

View File

@@ -0,0 +1,134 @@
package com.alibaba.middleware.race.mom.broker.function;
import io.netty.channel.Channel;
import java.io.Serializable;
import com.alibaba.middleware.race.mom.Message;
/**
* 生产者生的产消息和其它信息封装
* @author youngforever
*
*/
public class MessageInfo implements Serializable{
private static final long serialVersionUID = 529580833582395809L;
/**
* 由broker端设置,需要再加
*/
private Message msg;
// private String producerId;
// private String producerGroupId;
private String msgInfoId;
private Channel producer;
private int queueId;
private int offset;//存储顺序,是topicandfilter下 某个queueId 下的offset
public MessageInfo(Message msg, Channel producer){
this.msg = msg;
this.producer = producer;
}
public MessageInfo(Message msg, Channel producer, int queueId, int offset) {
this.msg = msg;
this.producer = producer;
this.queueId = queueId;
this.offset = offset;
}
/**
* msg 订阅集群数
*/
// private AtomicInteger subGroupsCount;
// public MessageInfo(Message msg, String producerId, String producerGroupId) {
// this.msg = msg;
// this.producerId = producerId;
// this.producerGroupId = producerGroupId;
// }
//
public Message getMsg() {
return msg;
}
public void setMsg(Message msg) {
this.msg = msg;
}
// public int getSubGroupsCount() {
// return subGroupsCount.get();
// }
//
// public void setSubGroupsCount(int subGroupsCount) {
// this.subGroupsCount = new AtomicInteger(subGroupsCount);
// }
// public int decreSubGroupsCount(){
// return subGroupsCount.decrementAndGet();
// }
// public String getProducerId() {
// return producerId;
// }
public String getMsgInfoId() {
return msgInfoId;
}
public void setMsgInfoId(String msgInfoId) {
this.msgInfoId = msgInfoId;
}
public int getQueueId() {
return queueId;
}
public int getQueueIndex() {
return queueId;
}
public void setQueueId(int queueId) {
this.queueId = queueId;
}
// public void setProducerId(String producerId) {
// this.producerId = producerId;
// }
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
// public String getProducerGroupId() {
// return producerGroupId;
// }
//
//
// public void setProducerGroupId(String producerGroupId) {
// this.producerGroupId = producerGroupId;
// }
public Channel getProducer() {
return producer;
}
/**
*由broker 端设置,连接成功后,设置生产者channel,以便精确返回ack
* @param producer
*/
public void setProducer(Channel producer) {
this.producer = producer;
}
}

View File

@@ -0,0 +1,31 @@
package com.alibaba.middleware.race.mom.broker.function;
import io.netty.channel.Channel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import com.alibaba.middleware.race.mom.QueueMessage;
public class MessageInfoQueue {
private Channel producer;
private BlockingQueue<QueueMessage> msgQueue;
private String topic;
private Map<String, String> properties = new HashMap<String, String>();
private String msgQueueId;
public MessageInfoQueue(BlockingQueue<QueueMessage> msgQueue, String topic,
Map<String, String> properties) {
super();
this.msgQueue = msgQueue;
this.topic = topic;
this.properties = properties;
}
}

View File

@@ -0,0 +1,344 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.Message;
import com.alibaba.middleware.race.mom.broker.group.ConsumerGroup;
import com.alibaba.middleware.race.mom.broker.group.ProducerGroup;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
public class MessageManager {
private static org.slf4j.Logger logger = LoggerFactory.getLogger(MessageManager.class);
// public static Map<String/* TopicAndFilter+msgOffset */,MessageInfo> messageCacheMap;
/**
* 每个集群有独立的消费进度
* 消息再broker收到后,按照TopicAndFilter 消息分类,每种TopicAndFilter消息有独立的offsetProducer
* 如果要以queueId分多文件,那么再分一层独立的offsetProducer
*/
// private MsgStore mstore = /* new MsgStoreImp();// */new MsgStoreImp_MappedBuffer();
// private FSTConfiguration fst = FSTConfiguration.getDefaultConfiguration();
// private Map<String/* topic@group */,BlockingQueue<String /*id*/>/*reSendMsgQueue*/>topicAndgroup2reSendMsgQueue=new HashMap<>();
// public MessageManager(ConcurrentHashMap<String/* TopicAndFilter+msgOffset */,Message> recoverMsgMap){
// if(recoverMsgMap!=null){
// messageCacheMap=recoverMsgMap;
// }else{
// messageCacheMap=new ConcurrentHashMap<>();
// }
// }
/**
* 打包消息处理
* @param msgSend
* @param producer
*/
public static void recieveMsg(MessageSend msgSend,ChannelHandlerContext producer){
long start=System.currentTimeMillis();
/*
* 存储处理
*/
msgSend.setProducer(producer.channel());
TopicAndFilter topicAndFilter=new TopicAndFilter(msgSend.getTopic(),msgSend.getProperties());
String queueIdAndOffsetArray[] = ProducerGroup.storeMsg(topicAndFilter,msgSend).split(" ");
int queueIndex=Integer.parseInt(queueIdAndOffsetArray[0]);
int offset=Integer.parseInt(queueIdAndOffsetArray[1]);
logger.debug("currentCanUseOffset "+offset);
/*
* 消息进入待发送队列,等待存储完成()
*/
int i=0;
for(byte[]body:msgSend.getBodys()){
Message msg=new Message(msgSend.getTopic(),body,msgSend.getProperties(),msgSend.getBornTime());
msg.setMsgId(msgSend.getSendIds().get(i));
MessageInfo msgInfo=new MessageInfo(msg,producer.channel());
msgInfo.setQueueId(queueIndex);
msgInfo.setOffset(offset++);
msgInfo.setMsgInfoId(topicAndFilter.toString()+queueIndex+""+String.valueOf(msgInfo.getOffset()));
/*
* 发送处理,加入发送队列,等待存储完成
*/
ConsumerGroup.sendMsg(topicAndFilter, msgInfo);
i++;
}
// logger.error("消息born 到生产者recv处理完毕 cost"+(System.currentTimeMillis()-msgSend.getBornTime()));
// logger.error("消息recv生产者recv处理完毕 cost"+(System.currentTimeMillis()-start));
}
/**
* 接收到生产者 消息,触发一系列处理
* @param msg
* @param producer
*/
// public static void recieveMsg(Message msg,ChannelHandlerContext producer){
// //生产者信息构建的topicAndFilter
// TopicAndFilter topicAndFilter=new TopicAndFilter(msg.getTopic(),msg.getProperties());
//// String topicAndFilterString=topicAndFilter.toString();
// /**
// * broker端给消息的编号:offset,同时对应存储位置,消费进度
// * topicAndFilter不同,offset将相互独立
// */
//// //broker端给消息的编号:offset,同时对应存储位置,消费进度
//// if(offsetProducerMap.containsKey(topicAndFilterString)){
//// int offset=offsetProducerMap.get(topicAndFilterString).getAndIncrement();
//// msg.setOffset(offset);
//// }
// /**
// * 以下两个过程,保证:
// * 一.先加入持久化队列(以持久化队列下标编offset(对应消息在文件中的索引),保证正确对应(也不会受多线程影响)),再加入发送队列
// * 二.保证每一条消息到磁盘(存储底层也已经强行force),再返回ack
// * 三.发送队列与持久化队列一一对应(其实也可以允许队列均衡导致不一致,但大的来说顺序仍然一致),保证消费进度的正确性(我们可以通过配置,每一个topicandfilter下做几个队列)
// * 四.发送给消费者与消息存储,多线程执行,不保证先后顺序(理想是并行)
// */
// long start=System.currentTimeMillis();
// MessageInfo msgInfo=new MessageInfo(msg,producer.channel());
// //持久化消息,成功后返回给生产者ack
// String queueIdAndOffsetArray[]=ProducerGroup.storeMsg(topicAndFilter,msgInfo).split(" ");
// int queueIndex=Integer.parseInt(queueIdAndOffsetArray[0]);
// int offset=Integer.parseInt(queueIdAndOffsetArray[1]);
// msgInfo.setQueueId(queueIndex);
// msgInfo.setOffset(offset);
// //消息对象引用存入内存map,为了避免多topicAndFilter时,map key重复,key以topicAndFilter+offset
//// msg.setOffset(offset);
//// MessageManager.addMessage(topicAndFilterString+String.valueOf(offset),msgInfo);
// //转发给发送消费者
// ConsumerGroup.sendMsg(topicAndFilter, msgInfo);
//
//// mstore.writeByteNormal(topicAndfilter.toString(),"t","t",0+"" , msgbytes/*caches*/);
//// ProducerGroup.addProducer(producer.channel(),"PROO", topicAndFilter);
//// producer.channel().writeAndFlush(msg.getMsgId() + "\r\n");
// //接收新消息处理完成,等待消费结果,进入消费结果处理
// logger.error("消息born 到生产者recv处理完毕 cost"+(System.currentTimeMillis()-msg.getBornTime()));
// logger.error("消息recv生产者recv处理完毕 cost"+(System.currentTimeMillis()-start));
// }
// public static void recieveMsg(BlockingQueue<MessageInfo> msgInfoqueue,ChannelHandlerContext producer){
// MessageInfo msgInfo=msgInfoqueue.peek();
// //生产者信息构建的topicAndFilter
// TopicAndFilter topicAndFilter=new TopicAndFilter(msgInfo.getMsg().getTopic(),msgInfo.getMsg().getProperties());
// String topicAndFilterString=topicAndFilter.toString();
// /**
// * broker端给消息的编号:offset,同时对应存储位置,消费进度
// * topicAndFilter不同,offset将相互独立
// */
//// //broker端给消息的编号:offset,同时对应存储位置,消费进度
//// if(offsetProducerMap.containsKey(topicAndFilterString)){
//// int offset=offsetProducerMap.get(topicAndFilterString).getAndIncrement();
//// msg.setOffset(offset);
//// }
// /**
// * 以下两个过程,保证:
// * 一.先加入持久化队列(以持久化队列下标编offset(对应消息在文件中的索引),保证正确对应(也不会受多线程影响)),再加入发送队列
// * 二.保证每一条消息到磁盘(存储底层也已经强行force),再返回ack
// * 三.发送队列与持久化队列一一对应(其实也可以允许队列均衡导致不一致,但大的来说顺序仍然一致),保证消费进度的正确性(我们可以通过配置,每一个topicandfilter下做几个队列)
// * 四.发送给消费者与消息存储,多线程执行,不保证先后顺序(理想是并行)
// */
// msgInfo.setProducer(producer.channel());
// MessageInfoQueue msgQueue=new MessageInfoQueue(producer.channel(),topicAndFilter,msgInfoqueue);
//
// //持久化消息,成功后返回给生产者ack
// ProducerGroup.storeMsg(topicAndFilter,msgQueue);
//// int queueIndex=Integer.parseInt(queueIdAndOffsetArray[0]);
//// int offset=Integer.parseInt(queueIdAndOffsetArray[1]);
//// msgInfo.setQueueId(queueIndex);
//// msgInfo.setOffset(offset);
// //消息对象引用存入内存map,为了避免多topicAndFilter时,map key重复,key以topicAndFilter+offset
//// msg.setOffset(offset);
//// MessageManager.addMessage(topicAndFilterString+String.valueOf(offset),msgInfo);
// //转发给发送消费者
// ConsumerGroup.sendMsg(topicAndFilter, msgInfo);
//
//// mstore.writeByteNormal(topicAndfilter.toString(),"t","t",0+"" , msgbytes/*caches*/);
//// ProducerGroup.addProducer(producer.channel(),"PROO", topicAndFilter);
//// producer.channel().writeAndFlush(msg.getMsgId() + "\r\n");
// //接收新消息处理完成,等待消费结果,进入消费结果处理
// }
// public static void addMessage(String offet,MessageInfo msgInfo){
// messageCacheMap.put(offet, msgInfo);
// }
// public static void setMsgMap(ConcurrentHashMap<String/* TopicAndFilter+msgOffset */,MessageInfo> recoverMap){
// messageCacheMap=recoverMap;
// }
/**
* 开始存储任务
*/
// long starttttt;
// public void startStore(){
//
//// for(final BlockingQueue<MessageInfo> storeQueue:storeQueues){
//// for(int i=0;i<storeThreadPoolSize/storeQueueNum;i++){//每个队列提交几次任务,占满线程池
// storePool.execute(new Runnable(){
// @Override
// public void run() {
// long start=System.currentTimeMillis();
// AtomicInteger storeCount=new AtomicInteger();
// BlockingQueue<MessageInfo> storeQueue=storeQueues.get(0);
// while(true){
// MessageInfo msgInfo=null;
// ArrayList<byte[]> msgbytes=new ArrayList<>();
// StoreSucceedListener storeSucceedListener=new StoreSucceedListener();
// /**
// * 准备一次存储过程,构建对应存储成功监听器
// */
//// int i=100;
//// try {
//// count.await(20, TimeUnit.MILLISECONDS);
//// } catch (InterruptedException e) {
//// count=new CountDownLatch(100);
//// }
//// boolean flag=false;
//// while(!storeQueue.isEmpty()&&i-->0){
//
// int offset=0;
//
// while(true){
//// if(storeCount.incrementAndGet()>98){
//// System.out.println("一百条等待"+(System.currentTimeMillis()-start));
//// break;
//// };
// try {
// msgInfo=storeQueue.poll(0, TimeUnit.MILLISECONDS);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// if(msgInfo==null&&storeCount.get()==0) continue;
// if(msgInfo==null) continue;
// offset=msgInfo.getOffset();
// redo.writeLog2(offset+"", msgInfo.getMsg().getTopic(), msgInfo.getQueueId(),msgInfo.getMsg().getBody());
//// i++;
//
//// storeSucceedListener.addAckWaiter(msgInfo.getProducer(), msgInfo.getMsg().getMsgId());
// storeSucceedListener.addAckWaiterGroup(msgInfo.getProducer(), msgInfo.getMsg().getMsgId());
//
//// if(cando&&storeCount.get()!=0) break;
// if(storeCount.incrementAndGet()>199) break;
//// flag=true;
////
// }
//// if(flag)
// if(storeCount.get()==0) continue;
// logger.error(Thread.currentThread().getName()+" "+(System.currentTimeMillis()-start)+" ms后提交新落盘任务,一次flush"+storeCount.get()+"条");
//// storeTask(storeQueues.indexOf(storeQueue),msgbytes,storeSucceedListener,offset);
//
// long submit=System.currentTimeMillis();
// if(starttttt==0){
// starttttt=submit;
// }
// redo.flushLog();
// logger.error("redo"+(System.currentTimeMillis()-starttttt));
// storeSucceedListener.onStoreSucceed(topicAndfilter,0,offset);
// storeCount.set(0);
// start =System.currentTimeMillis();
//// }else{
//// //0就不提交了大量废任务进入线程池。。。
//// }
// }
// }
// });
//// }
//// for(int i=0;i<storeThreadPoolSize/storeQueueNum;i++){//每个队列提交几次任务,占满线程池
// storePool.execute(new Runnable(){
// @Override
// public void run() {
// long start=System.currentTimeMillis();
// AtomicInteger storeCount=new AtomicInteger();
// BlockingQueue<MessageInfo> storeQueue=storeQueues.get(1);
// while(true){
// MessageInfo msgInfo=null;
// ArrayList<byte[]> msgbytes=new ArrayList<>();
// StoreSucceedListener storeSucceedListener=new StoreSucceedListener();
// /**
// * 准备一次存储过程,构建对应存储成功监听器
// */
//// int i=100;
//// try {
//// count.await(20, TimeUnit.MILLISECONDS);
//// } catch (InterruptedException e) {
//// count=new CountDownLatch(100);
//// }
//// boolean flag=false;
//// while(!storeQueue.isEmpty()&&i-->0){
//
// int offset=0;
//
// while(true){
//// if(storeCount.incrementAndGet()>98){
//// System.out.println("一百条等待"+(System.currentTimeMillis()-start));
//// break;
//// };
// try {
// msgInfo=storeQueue.poll(0, TimeUnit.MILLISECONDS);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// if(msgInfo==null&&storeCount.get()==0) continue;
// if(msgInfo==null) continue;
// offset=msgInfo.getOffset();
// redo2.writeLog2(offset+"", msgInfo.getMsg().getTopic(), msgInfo.getQueueId(),msgInfo.getMsg().getBody());
//// i++;
//
//// storeSucceedListener.addAckWaiter(msgInfo.getProducer(), msgInfo.getMsg().getMsgId());
// storeSucceedListener.addAckWaiterGroup(msgInfo.getProducer(), msgInfo.getMsg().getMsgId());
//
//// if(cando&&storeCount.get()!=0) break;
// if(storeCount.incrementAndGet()>99) break;
//// flag=true;
////
// }
//// if(flag)
// if(storeCount.get()==0) continue;
// logger.error(Thread.currentThread().getName()+" "+(System.currentTimeMillis()-start)+" ms后提交新落盘任务,一次flush"+storeCount.get()+"条");
//// storeTask(storeQueues.indexOf(storeQueue),msgbytes,storeSucceedListener,offset);
// long submit=System.currentTimeMillis();
// if(starttttt==0){
// starttttt=submit;
// }
// redo2.flushLog();
// logger.error("redo2 "+(System.currentTimeMillis()-starttttt));
// storeSucceedListener.onStoreSucceed(topicAndfilter,1,offset);
// storeCount.set(0);
// start =System.currentTimeMillis();
//// }else{
//// //0就不提交了大量废任务进入线程池。。。
//// }
// }
// }
// });
//// }
//
//
// }
// }
}

View File

@@ -0,0 +1,91 @@
package com.alibaba.middleware.race.mom.broker.function;
import io.netty.channel.Channel;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class MessageSend implements Serializable{
private static final long serialVersionUID = 1980989080980980L;
private ArrayList<String> sendIds=new ArrayList<>();
private String topic;
private ArrayList<byte[]> bodys=new ArrayList<>();
private Map<String, String> properties = new HashMap<String, String>();
private long bornTime=System.currentTimeMillis();
private Channel producer;
public MessageSend(){}
public ArrayList<String> getSendIds() {
return sendIds;
}
public void setSendIds(ArrayList<String> sendIds) {
this.sendIds = sendIds;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public ArrayList<byte[]> getBodys() {
return bodys;
}
public void setBodys(ArrayList<byte[]>bodys) {
this.bodys = bodys;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
public long getBornTime() {
return bornTime;
}
public void setBornTime(long bornTime) {
this.bornTime = bornTime;
}
public MessageSend( String topic,
Map<String, String> properties) {
this.topic = topic;
this.properties = properties;
}
public MessageSend( String topic
) {
this.topic = topic;
}
public Channel getProducer() {
return producer;
}
public void setProducer(Channel producer) {
this.producer = producer;
}
}

View File

@@ -0,0 +1,356 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.config.Config;
import com.alibaba.middleware.race.mom.store.RedoLog;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
/**
* 每个生产者集群(组)有一个MessageStore,用于存储此集群(组)(对应一种TopicAndFilter)的消息,也即每个生产者集群(组)一个storeQueues
* @author youngforever
*
*/
public class MessageStore {
private static Logger logger = LoggerFactory.getLogger(MessageStore.class);
/**
* 注意这里要和sendqueuenum 一致,全局统一配置
*/
private int storeQueueNum=Config.maxqueue;
/**
*支持分布式队列(分布式存储任务),默认一个存储队列
*/
// private LinkedList<BlockingQueue<MessageInfo /*msg*/>> storeQueues = new LinkedList<>();
private LinkedList<BlockingQueue<MessageSend /*msg*/>> storeGroupQueues = new LinkedList<>();
private int storeThreadPoolSize = storeQueueNum;
private AtomicInteger[] offsetMakers=new AtomicInteger[storeQueueNum];
private ExecutorService storePool = Executors.newFixedThreadPool(storeThreadPoolSize);
// private ExecutorService flushPool = Executors.newSingleThreadExecutor();
private ExecutorService flushPool = Executors.newFixedThreadPool(storeQueueNum);
// private MsgStore mstore = /* new MsgStoreImp();// */new MsgStoreImp_MappedBuffer2();
// private FSTConfiguration fst = FSTConfiguration.getDefaultConfiguration();
private TopicAndFilter topicAndfilter;
// private Store store=new Store();
// Redo redo=new Redo();
// redotest redo=new redotest();
RedoLog storer=new RedoLog();
// CountDownLatch count=new CountDownLatch(1);
volatile boolean cando=false;
private boolean messageGroup=false;
// private AtomicInteger recvCount=new AtomicInteger();
/**
* 用于恢复时,为了衔接故障前的状态
* @param topicAndfilter
* @param queueMaxOffsets
*/
public MessageStore(TopicAndFilter topicAndfilter,Map<Integer /*queueIndex*/,Integer/*maxOffset*/> queueMaxOffsets) {
this.topicAndfilter = topicAndfilter;
/*
* 创建时初始化队列
*/
// for(Map.Entry<Integer,Integer> queueMaxOffset:queueMaxOffsets.entrySet()){
// this.storeQueues.add(new LinkedBlockingQueue<MessageInfo>());
// offsetMakers[queueMaxOffset.getKey()]=new AtomicInteger(queueMaxOffset.getValue());
// }
for(Map.Entry<Integer,Integer> queueMaxOffset:queueMaxOffsets.entrySet()){
this.storeGroupQueues.add(new LinkedBlockingQueue<MessageSend>());
offsetMakers[queueMaxOffset.getKey()]=new AtomicInteger(queueMaxOffset.getValue());
}
// startStore();
startStoreGroup();
}
/**
* 用于新增
* @param topicAndfilter
*/
public MessageStore(TopicAndFilter topicAndfilter) {
this.topicAndfilter = topicAndfilter;
/*
* 创建时初始化队列
*/
// for(int i=0;i<storeQueueNum;i++){
// this.storeQueues.add(new LinkedBlockingQueue<MessageInfo>());
// offsetMakers[i]=new AtomicInteger();
// }
for(int i=0;i<storeQueueNum;i++){
this.storeGroupQueues.add(new LinkedBlockingQueue<MessageSend>());
offsetMakers[i]=new AtomicInteger();
}
// startStore();
/*
* 采用组发,则不必盯着队列
*/
// startStoreGroup();
}
/**
* 存储队列均衡
* @return
*/
// private int storeQueueBalancer=-1;
// public synchronized BlockingQueue<MessageInfo> storeQueuesBalance(){
// storeQueueBalancer++;
// if(storeQueueBalancer==storeQueueNum){
// storeQueueBalancer=0;
// }
// BlockingQueue<MessageInfo> storeQueue=storeQueues.get(storeQueueBalancer);
// return storeQueue;
// }
private int storeGroupQueueBalancer=-1;
public synchronized BlockingQueue<MessageSend> storeQueuesBalance(boolean isGroup){
storeGroupQueueBalancer++;
if(storeGroupQueueBalancer==storeQueueNum){
storeGroupQueueBalancer=0;
}
BlockingQueue<MessageSend> storeGroupQueue=storeGroupQueues.get(storeGroupQueueBalancer);
return storeGroupQueue;
}
/**
* 加入均衡后的存储队列
* @param msg
* @return queueId+" "+offset
*/
// public String storeMsg(MessageInfo msgInfo){
//// System.out.println(recvCount.incrementAndGet());
//
// BlockingQueue<MessageInfo> storeQueue=storeQueuesBalance();
// int queueId=storeQueues.indexOf(storeQueue);
// int offset;
// synchronized(this){//同步块中进行,保证offset的准确性(存储队列中加入和offet产生的原子性)
//// count.countDown();
// storeQueue.offer(msgInfo);
// offset=offsetMakers[queueId].getAndIncrement();
// }
// return String.valueOf(queueId)+" "+String.valueOf(offset);
// }
/**
* 加入均衡后的组存 存储队列
* @param msgSend
* @return
*/
public String storeMsg(MessageSend msgSend){
BlockingQueue<MessageSend> storeGroupQueue=storeQueuesBalance(true);
int queueId=storeGroupQueues.indexOf(storeGroupQueue);
int offset;
synchronized(this){//同步块中进行,保证offset的准确性(存储队列中加入和offet产生的原子性)
// count.countDown();
//offset从0开始所以返回的就是当前可用的起始offset
offset=offsetMakers[queueId].getAndAdd(msgSend.getBodys().size());
storeGroupQueue.offer(msgSend);
}
startStoreGroup();
return String.valueOf(queueId)+" "+String.valueOf(offset);
}
// public void storeMsg(MessageInfoQueue msgInfoQueue){
//// System.out.println(recvCount.incrementAndGet());
//
// BlockingQueue<MessageInfo> storeQueue=storeQueuesBalance();
//// int queueId=storeQueues.indexOf(storeQueue);
//// int offset;
//// count.countDown();
// storeQueue.addAll(msgInfoQueue.getMsgInfoqueue());
//// offset=offsetMakers[queueId].getAndIncrement();
//// }
//// return String.valueOf(queueId)+" "+String.valueOf(offset);
// }
/**
* 一次存储过程
*/
public void storeTask(final int queueIndex,ArrayList<byte[]> msgbytes,final StoreSucceedListener storeSucceedListener,final int offset){
flushPool.execute(new Runnable(){
//
// @Override
public void run() {
cando=false;
final long start=System.currentTimeMillis();
// store.flush();
storer.flushLog();
// redo.flushLog();
// try {
// Thread.sleep(15);
// } catch (InterruptedException e) {
// }
// logger.error("一次flush cost:"+(System.currentTimeMillis()-start));
// mstore.writeByteNormal( topicAndfilter.toString(), String.valueOf(queueIndex), msgbytes);
cando=true;
storeSucceedListener.onStoreSucceed(topicAndfilter,queueIndex,offset);
}
});
}
/**
* 组存任务开始
*/
public void startStoreGroup(){
for(final BlockingQueue<MessageSend> storeGroupQueue:storeGroupQueues){
for(int i=0;i<storeThreadPoolSize/storeQueueNum;i++){//每个队列提交几次任务,占满线程池
storePool.execute(new Runnable(){
@Override
public void run() {
long start=System.currentTimeMillis();
AtomicInteger storeCount=new AtomicInteger();
MessageSend msgSend=null;
ArrayList<byte[]> msgbytes=new ArrayList<>();
StoreSucceedListener storeSucceedListener=new StoreSucceedListener();
/**
* 准备一次存储过程,构建对应存储成功监听器
*/
// int i=100;
// try {
// count.await(20, TimeUnit.MILLISECONDS);
// } catch (InterruptedException e) {
// count=new CountDownLatch(100);
// }
// boolean flag=false;
// while(!storeQueue.isEmpty()&&i-->0){
//队列对应本次存储成功的条数
int offset=0;
while(!storeGroupQueue.isEmpty()){
msgSend=storeGroupQueue.poll();
if(msgSend==null) break;
storer.writeLog(msgSend.getTopic(), msgSend.getProperties().toString(),storeGroupQueues.indexOf(storeGroupQueue) , msgSend.getBodys());
offset=msgSend.getBodys().size();
// redo.writeLog(topic/*String*/, filter/*String*/,queueindex/*Integer*/,bodys/*(200个byte[])/*ArrayList<byte[]>*/);
// for(byte[] body:msgSend.getBodys()){
//// redo.writeLog2(body);
// offset++;
// storeCount.incrementAndGet();
// }
// i++;
// storeSucceedListener.addAckWaiter(msgSend.getProducer(), msgSend.getMsg().getMsgId());
// storeSucceedListener.addAckWaiterGroup(msgSend.getProducer(), msgSend.getMsg().getMsgId());
// storeSucceedListener.addAckWaiterNum(msgSend.getProducer());
// if(cando&&storeCount.get()!=0) break;
// flag=true;
//
storeSucceedListener.addAckGroupWaiter(msgSend.getProducer(),msgSend.getSendIds());
}
// if(flag)
if(offset!=0){
// logger.error((System.currentTimeMillis()-start)+" ms后提交新落盘任务,一次flush"+offset+"条");
// logger.error("一共flush"+storeCount.get()*offset+"条");
storeTask(storeGroupQueues.indexOf(storeGroupQueue),msgbytes,storeSucceedListener,offset);
storeCount.set(0);
// start =System.currentTimeMillis();
// }else{
// //0就不提交了大量废任务进入线程池。。。
// }
}
}
});
}
}
}
//
// /**
// * 开始存储任务
// */
// public void startStore(){
//
// for(final BlockingQueue<MessageInfo> storeQueue:storeQueues){
// for(int i=0;i<storeThreadPoolSize/storeQueueNum;i++){//每个队列提交几次任务,占满线程池
// storePool.execute(new Runnable(){
// @Override
// public void run() {
// int count=0;
// long start=System.currentTimeMillis();
// AtomicInteger storeCount=new AtomicInteger();
// while(true){
// MessageInfo msgInfo=null;
// ArrayList<byte[]> msgbytes=new ArrayList<>();
// StoreSucceedListener storeSucceedListener=new StoreSucceedListener();
// /**
// * 准备一次存储过程,构建对应存储成功监听器
// */
//// int i=100;
//// try {
//// count.await(20, TimeUnit.MILLISECONDS);
//// } catch (InterruptedException e) {
//// count=new CountDownLatch(100);
//// }
//// boolean flag=false;
//// while(!storeQueue.isEmpty()&&i-->0){
//
// int offset=0;
//
// while(true){
//// if(storeCount.incrementAndGet()>98){
//// System.out.println("一百条等待"+(System.currentTimeMillis()-start));
//// break;
//// };
//
// try {
// if(!messageGroup){
// msgInfo=storeQueue.poll(500, TimeUnit.MILLISECONDS);
// if(storeCount.get()>1){
// messageGroup=true;
// }
// }else msgInfo=storeQueue.poll();
//
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// if(msgInfo==null&&!messageGroup&&storeCount.get()==1)break;
// if(msgInfo==null&&storeCount.get()==0) continue;
// if(msgInfo==null) continue;
// offset=msgInfo.getOffset();
// redo.writeLog(offset+"", msgInfo.getMsg().getTopic(),msgInfo.getMsg().getBody());
//// i++;
//
//// storeSucceedListener.addAckWaiter(msgInfo.getProducer(), msgInfo.getMsg().getMsgId());
//// storeSucceedListener.addAckWaiterGroup(msgInfo.getProducer(), msgInfo.getMsg().getMsgId());
//// storeSucceedListener.addAckWaiterNum(msgInfo.getProducer());
//// if(cando&&storeCount.get()!=0) break;
//// flag=true;
// if(storeCount.incrementAndGet()>199){
// messageGroup=true;
// break;
// }
////
// }
//// if(flag)
// if(storeCount.get()==0) continue;
// count++;
// messageGroup=true;
//// logger.error((System.currentTimeMillis()-start)+" ms后提交新落盘任务,一次flush"+storeCount.get()+"条");
// logger.error("一共flush"+storeCount.get()*count+"条");
// storeTask(storeQueues.indexOf(storeQueue),msgbytes,storeSucceedListener,offset);
// storeCount.set(0);
// start =System.currentTimeMillis();
//// }else{
//// //0就不提交了大量废任务进入线程池。。。
//// }
// }
// }
// });
// }
// }
// }
}

View File

@@ -0,0 +1,169 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.io.Serializable;
import java.util.Map;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
public class Offset implements Serializable{
private static final long serialVersionUID = -7988990980809880981L;
/**
* 消息信息,生产者集群信息
*/
private String topic;
private Map<String,String> filter;
// private TopicAndFilter topicAndFilter;
// private String groupId;
/**
* 存储采用多队列多文件时采用
*/
private int queueIndex;
/**
* 消费者集群信息,姑且不需要,因为恢复 会重新发起订阅
*/
/**
* 与存储顺序(拉取索引)对应的 消费进度表示
*/
int currentOffset=-1; //当前消费进度
/**
* 存储成功的最大maxOffset;msg 的offset>此maxOffset,即为加入存储队列但是尚未存储(强行force)到磁盘,保证存储成功后,才来调用设置这个值
*/
int maxOffset=-1; //最大偏移(size)
public Offset(){
};
// public Offset(TopicAndFilter topicAndFilter){
// this.topicAndFilter=topicAndFilter;
// }
/*function*/
public void addCacheMaxOffsetBy(int size)
{
// this.cacheOffset+=size;
}
public void addMaxOffsetBy(int size)
{
this.maxOffset+=size;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public Map<String, String> getFilter() {
return filter;
}
public void setFilter(Map<String, String> filter) {
this.filter = filter;
}
public void setCurrentOffsetBy(int size)
{
if(size>this.currentOffset)
this.currentOffset=size;
}
// public String getGroupId() {
// return groupId;
// }
// public void setGroupId(String groupId) {
// this.groupId = groupId;
// }
public int getQueueIndex() {
return queueIndex;
}
public void setQueueIndex(int queueIndex) {
this.queueIndex = queueIndex;
}
public int getCurrentoffset() {
return currentOffset;
}
public void setCurrentoffset(int currentoffset) {
this.currentOffset = currentoffset;
}
// public int getCacheOffset() {
// return cacheOffset;
// }
// public void setCacheOffset(int cacheOffset) {
// this.cacheOffset = cacheOffset;
// }
public int getMaxOffset() {
return maxOffset;
}
public void setMaxOffset(int maxOffset) {
this.maxOffset = maxOffset;
}
// public String getTopic() {
// return topic;
// }
// public void setTopic(String topic) {
// this.topic = topic;
// }
// public TopicAndFilter getTopicAndFilter() {
// return topicAndFilter;
// }
// public void setTopicAndFilter(TopicAndFilter topicAndFilter) {
// this.topicAndFilter = topicAndFilter;
// }
// @Override
// public String toString() {
// return "Offset: [topicAndFilter=" + topicAndFilter + ", queueIndex=" + queueIndex
// + ", currentoffset=" + currentOffset + ", MaxOffset=" + maxOffset
// + "]";
// }
@Override
public String toString() {
return "Offset: [topic=" + topic+"filter:"+filter + ", queueIndex=" + queueIndex
+ ", currentoffset=" + currentOffset + ", MaxOffset=" + maxOffset
+ "]";
}
// @Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + maxOffset;
result = prime * result + currentOffset;
// result = prime * result + ((queueIndex == 0) ? 0 : queueIndex.hashCode());
// result = prime * result + ((topicAndFilter == null) ? 0 : topicAndFilter.hashCode());
result = prime * result + ((topic == null) ? 0 : topic.hashCode());
result = prime * result + ((filter == null) ? 0 : filter.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Offset other = (Offset) obj;
if (maxOffset != other.maxOffset)
return false;
// if (cacheOffset != other.cacheOffset)
// return false;
if (currentOffset != other.currentOffset)
return false;
// if (topicAndFilter == null) {
// if (other.topicAndFilter != null)
// return false;
// } else if (!topicAndFilter.equals(other.topicAndFilter))
// return false;
if (queueIndex != other.queueIndex) {
return false;
}
if (topic == null) {
if (other.topic != null)
return false;
} else if (!topic.equals(other.topic))
return false;
return true;
}
}

View File

@@ -0,0 +1,88 @@
//package com.alibaba.middleware.race.mom.broker.function;
//
//import io.netty.channel.Channel;
//
//import java.util.concurrent.BlockingQueue;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.LinkedBlockingQueue;
//
//import com.alibaba.middleware.race.mom.Message;
//import com.alibaba.middleware.race.mom.broker.group.ConsumerGroup;
//import com.alibaba.middleware.race.mom.util.TopicAndFilter;
///**
// * 每个集群有自己的ReSendHandler
// * @author youngforever
// *
// */
//public class ReSendHandler {
// private TopicAndFilter topicAndFilter;
// private ConsumerGroup group;
// public BlockingQueue<Integer> reSendQueue=new LinkedBlockingQueue<Integer>();
//
// int reSendThreadPoolSize=2;
// private ExecutorService reSendPool = Executors.newFixedThreadPool(reSendThreadPoolSize);
//
//
// public ReSendHandler(TopicAndFilter topicAndFilter, ConsumerGroup group) {
// this.topicAndFilter = topicAndFilter;
// this.group = group;
// }
// public void consumerLostReSend(){
//
// }
// public void timeoutReSend(){
//
// }
// public void failReSend(){
//
// }
//
//
// /**
// * 开始发送任务
// */
// public void startRend(){
// for(int i=0;i<reSendThreadPoolSize;i++){//每个队列提交几次任务,占满线程池
// reSendPool.execute(new Runnable(){
// int offset;
// Message msg;
// Channel consumer;
// @Override
// public void run() {
// while(true){
// try {
// offset=reSendQueue.take();
// } catch (InterruptedException e) {
// // 不可能出现线程中断异常的
// Thread.interrupted();//清除中断状态
// }
// //取消息,发送
// msg=MessageManager.messageCacheMap.get(topicAndFilter+String.valueOf(offset)).getMsg();
// if(msg==null){
// return;
// }
// consumer=group.consumersBalance();
// if(consumer!=null){
// consumer.writeAndFlush(msg);
// group.getSendInfoMap().get(msg.getMsgId()).setSendTime(System.currentTimeMillis());
// }else {
//// logger.error("消费者集群都不在线,须集群恢复后重投");
//
// }
//
//// //记录发送状态信息
//// SendInfo sendResult=new SendInfo(timeoutLimit);
//// sendResult.setNeedSendGroupNum(ConsumerGroup.needSendGroupsNum(topicAndFilter));
//// sendResult.setMsgOffset(msg.getOffset());
//// sendResult.setTopicAndFilter(topicAndFilter);
//// sendResult.setSendTime(System.currentTimeMillis());
//// sendResult.setStatus(ConsumerGroup.this,SendStatus.SEND);
//// sendInfoMap.put(msg.getMsgId(),sendResult);
// }
// }
// });
// }
// }
//
//}

View File

@@ -0,0 +1,144 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.nustaq.serialization.FSTConfiguration;
import com.alibaba.middleware.race.mom.Message;
import com.alibaba.middleware.race.mom.broker.group.ProducerGroup;
import com.alibaba.middleware.race.mom.store.MsgStore;
import com.alibaba.middleware.race.mom.store.MsgStoreImp_MappedBuffer2;
import com.alibaba.middleware.race.mom.store.SubscribeStore;
import com.alibaba.middleware.race.mom.store.SubscribeStoreImp;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
/**
* broker 故障重启恢复
* @author youngforever
*
*/
public class Recover {
private FSTConfiguration fst = FSTConfiguration.getDefaultConfiguration();
private SubscribeStore substore=new SubscribeStoreImp();
private MsgStore mstore = /* new MsgStoreImp();// */new MsgStoreImp_MappedBuffer2();
private int maxOffset;
public ConcurrentHashMap<String,Message> recover(){
return recoverMessage(makeOffsets(recoveroffsets()));
}
public ArrayList<Offset> recoveroffsets(){
ArrayList<Offset> offsets=substore.read();
System.out.println(offsets);
return offsets;
}
/**
* 集群组 进度重叠交叉等,对其取并集,避免从磁盘重复读取消息
* 遍历所有恢复的Offset,做其它恢复的准备和恢复消息去重
* @param offsets
* @return
*/
public List<Offset> makeOffsets(ArrayList<Offset>offsets ){
HashMap<TopicAndFilter,Offset>makedOffsets=new HashMap<>();
HashMap<TopicAndFilter/*TopicAndFilter*/,Map<Integer /*queueIndex*/,Integer/*maxOffset*/>>producerGroupRecoverInfos=new HashMap<>();
Offset makedoffset;
TopicAndFilter topicAndFilter;
for(Offset offset:offsets){
topicAndFilter=new TopicAndFilter(offset.getTopic(),offset.getFilter());
System.out.println(offset);
/*
* 恢复存储进度关系
*/
if(producerGroupRecoverInfos.containsKey(topicAndFilter)){
producerGroupRecoverInfos.get(topicAndFilter).put(offset.getQueueIndex(),offset.getMaxOffset());
}else{
Map<Integer /*queueIndex*/,Integer/*maxOffset*/> maxoffsets=new HashMap<>();
maxoffsets.put(offset.getQueueIndex(), offset.getMaxOffset());
producerGroupRecoverInfos.put(topicAndFilter, maxoffsets);
}
if(makedOffsets.containsKey(topicAndFilter)){
makedoffset=makedOffsets.get(topicAndFilter);
if(offset.getCurrentoffset()<makedoffset.getCurrentoffset()){
makedoffset.setCurrentoffset(offset.getCurrentoffset());
}
if(offset.getMaxOffset()>makedoffset.getMaxOffset()){
makedoffset.setMaxOffset(offset.getMaxOffset());
}
}else {
makedOffsets.put(topicAndFilter,offset);
}
}
ProducerGroup.recover(producerGroupRecoverInfos);
return Arrays.asList(makedOffsets.values().toArray(new Offset[0]));
}
public ConcurrentHashMap<String,Message> recoverMessage(List<Offset> makedOffsets){
long startTime = System.currentTimeMillis();
ConcurrentHashMap<String,Message> msgMap=new ConcurrentHashMap<>(1024*128);
System.out.println("offsets:"+makedOffsets);
int recoverNum=0;
int queueId;
TopicAndFilter topicAndFilter;
for(Offset offset:makedOffsets){
topicAndFilter=new TopicAndFilter(offset.getTopic(),offset.getFilter());
queueId=offset.getQueueIndex();
// //恢复topicAndgroup2subScribe
// LinkedList<Offset> offsetList;
// if(!topicAndgroup2subScribe.containsKey(topic+"@"+group)){
// offsetList=new LinkedList<Offset>();
// topicAndgroup2subScribe.put(topic+"@"+group, offsetList);
// }else{
// offsetList=topicAndgroup2subScribe.get(topic+"@"+group);
// }
// offsetList.add(Integer.parseInt(queueId),offset);
// //恢复topicAndgroup2sendMsgQueue
// LinkedList<BlockingQueue<String>> sendQueuesList;
// if(!topicAndgroup2sendMsgQueue.containsKey(topic + "@" + group)){
// sendQueuesList=new LinkedList<BlockingQueue<String>>();
// topicAndgroup2sendMsgQueue.put(topic + "@" + group, sendQueuesList);
// }else
// {
// sendQueuesList=topicAndgroup2sendMsgQueue.get(topic + "@" + group);
// }
// BlockingQueue<String>sendQueue=new LinkedBlockingQueue<String>();
// sendQueuesList.add(Integer.parseInt(queueId),sendQueue);
//消息入内存
int currentOffset=offset.getCurrentoffset();
int MaxOffset=offset.getMaxOffset();
Message msg;
int i=0;//currentOffset偏移量
List<byte[]> blist = mstore.readByteNormal(topicAndFilter.toString(),String.valueOf(queueId),currentOffset+1, MaxOffset);
recoverNum+=blist.size();
System.out.println(blist.size());
for(byte[] b:blist){
try{
msg=(Message)fst.asObject(b);
System.out.println("恢复消息"+msg);
}catch(Exception e){
continue;
}
msgMap.put(new TopicAndFilter(msg.getTopic(),msg.getProperties()).toString(), msg);
// msgid2offset.put(msg.getMsgId(), currentOffset+i);
i++;
}
}
long endTime = System.currentTimeMillis();
System.out.println("恢复cost" + (endTime - startTime)+" ,一共恢复"+recoverNum+"");
return msgMap;
}
public int getMaxOffset() {
return maxOffset;
}
}

View File

@@ -0,0 +1,136 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicInteger;
import com.alibaba.middleware.race.mom.SendStatus;
import com.alibaba.middleware.race.mom.config.Config;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
public class SendInfo implements Serializable {
/**
* 发送结果,判断消费是否超时等
*/
private static final long serialVersionUID = 321275686710864167L;
// public static final Map<String/* msgId */, SendInfo> sendInfoMap = new ConcurrentHashMap<>();
private MessageInfo msgInfo;
private String info;
private SendStatus status=SendStatus.SEND;
// private int msgOffset;
// private String topic;
/*
* 订阅集群的topicAndFilter
*/
private TopicAndFilter topicAndFilter;
// private int queueId;
private long sendTime;
// private long recvAckTime;
private long timeoutLimit=Config.timeoutLimit;
private AtomicInteger reSendCounter=new AtomicInteger();
public SendInfo(MessageInfo msgInfo){
this.msgInfo=msgInfo;
}
/**
* @param timeoutLimit unit:ms 允许的超时时间限制
*/
public SendInfo(MessageInfo msgInfo,long timeoutLimit){
this.msgInfo=msgInfo;
this.timeoutLimit=timeoutLimit;
}
/**
* 重置snedResult,用于重投时重投次数增加、重置发送时间,状态等
*
*/
public void reSend(){
sendTime=System.currentTimeMillis();
// recvAckTime=0;
reSendCounter.incrementAndGet();
this.status=SendStatus.RESEND;
}
public String getInfo() {
return info;
}
public SendStatus getStatus() {
return status;
}
public void setInfo(String info) {
this.info = info;
}
public void setStatus(SendStatus status) {
this.status= status ;
}
// public long getRecvAckTime() {
// return recvAckTime;
// }
// public void setRecvAckTime(long recvAckTime) {
// this.recvAckTime = recvAckTime;
// }
public void setSendTime(long sendTime){
this.sendTime=sendTime;
}
public long getSendTime(){
return this.sendTime;
}
public int getMsgOffset() {
return this.msgInfo.getOffset();
}
public TopicAndFilter getTopicAndFilter() {
return topicAndFilter;
}
public void setTopicAndFilter(TopicAndFilter topicAndFilter) {
this.topicAndFilter = topicAndFilter;
}
public int getQueueId() {
return this.msgInfo.getQueueIndex();
}
public MessageInfo getMsgInfo() {
return msgInfo;
}
public int getReSendCount() {
return reSendCounter.get();
}
// public void decreaseNeedSendGroupsNum(){
// needSendGroupsNum.decrementAndGet();
// }
/**
* @param nowTime
* @return 超时则 返回true;否则返回false;
*/
public boolean isTimeout(){
if(System.currentTimeMillis()-sendTime>=this.timeoutLimit){
this.status=SendStatus.TIMEOUT;
return true;
}else return false;
}
// public boolean canRemove(){
// if(status==SendStatus.SUCCESS){
// return true;
// }else if(this.reSendCounter.get()>=Config.maxReSendTime){
// return true;
// }else return false;
// }
/**
* @return 超时则 返回true;否则返回false;
* @throws Exception :throw exception if do not receive consumer's ACK or do not set the receive ACK time:recvAckTime
*/
// public boolean isTimeout() throws Exception{
// if(this.recvAckTime!=0){
// return recvAckTime-sendTime>=this.timeoutLimit;
// }else {
// throw new Exception("do not recieve consumer's ACK or do not set the recieve ACK time:recvAckTime ");
// }
// }
//
@Override
public String toString(){
return "msg "+msgInfo.getMsg()+" send "+status+" info:"+info;
}
}

View File

@@ -0,0 +1,191 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.SendStatus;
import com.alibaba.middleware.race.mom.broker.group.ConsumerGroup;
import com.alibaba.middleware.race.mom.config.Config;
import com.alibaba.middleware.race.mom.store.ArrayStore;
import com.alibaba.middleware.race.mom.store.ArrayStoreImp;
import com.alibaba.middleware.race.mom.store.OffsetNum;
/**
* 发送状态扫描器
* 一.负责检测消费超时,失败等,如果超时或失败加入重投
* 二.负责内存检测,一旦内存堆积过多超过内存大小警戒线,超时堆积消息将移除,保证系统正常运行以及正常消费tps
* @author young
*
*/
public class SendInfoScanner {
private static Logger logger = LoggerFactory.getLogger(SendInfoScanner.class);
private ConsumerGroup group;
private Timer timoutScannerTimer;
/**
* 重投配置
*/
private int timeoutLimit=10000;
private int maxReSendTime=10000000;
/**
* 重发线程池大小,也许可以调整大小来削峰谷
*/
private int reSendPoolSize=2;
private ExecutorService reSendPool;
private boolean reSendStarted=false;
/**
* 重投队列,死信队列,记得刷盘...TO DO.......................................................................
*/
private BlockingQueue<MessageInfo/*msgoffset*/> reSendQueue=new LinkedBlockingQueue<MessageInfo/*msgoffset*/>();
private BlockingQueue<MessageInfo/*msgoffset*/> deadMessageQueue=new LinkedBlockingQueue<MessageInfo/*msgoffset*/>();
private ArrayStore arrayStore=new ArrayStoreImp();
private AtomicInteger reSendFailCount=new AtomicInteger();
/**
* 重投恢复
*/
ExecutorService recoverPool=Executors.newFixedThreadPool(1);
public SendInfoScanner(ConsumerGroup group){
this.group=group;
}
public void start(){
scanSendInfoMap();
}
public void scanSendInfoMap(){
if(timoutScannerTimer==null){
timoutScannerTimer=new Timer();
}
timoutScannerTimer.schedule(new TimerTask(){
final Map <String,Map<String,ArrayList<OffsetNum>>> topicAndFilter2queues=new HashMap<>();
Map<String,ArrayList<OffsetNum>> queue2offsets;
ArrayList<OffsetNum> offsets;
Map<String,SendInfo> sendInfoMap=group.getSendInfoMap();
@Override
public void run() {
SendInfo sendInfo;
for(Map.Entry<String , SendInfo> entry:sendInfoMap.entrySet()){
sendInfo=entry.getValue();
if(sendInfo.getStatus()==SendStatus.TIMEOUT||sendInfo.getStatus()==SendStatus.FAIL||sendInfo.isTimeout()){
if(sendInfo.getReSendCount()<maxReSendTime){
// logger.error("消息"+sendInfo.getMsgId()+sendInfo.getStatus()+"加入重投队列");
if(!reSendStarted){//第一次此集群出现需要重投
startReSend();
reSendStarted=true;
}
/*
* 内存已经超出,应该移除重投部分部分
*/
// if(AccumulateHandler.full){
// if(sendInfoMap.size()>5000){
// logger.error("内存超出"+sendInfoMap.size());
// /*
// * 内存不足,存储重投部分offset
// */
// if((queue2offsets=topicAndFilter2queues.get(sendInfo.getTopicAndFilter().toString()))!=null){
// if((offsets=queue2offsets.get(String.valueOf(sendInfo.getQueueId())))!=null){
// offsets.add(new OffsetNum().setI(sendInfo.getMsgOffset()));
// }else{
// offsets=new ArrayList<OffsetNum>();
// offsets.add(new OffsetNum().setI(sendInfo.getMsgOffset()));
// queue2offsets.put(String.valueOf(sendInfo.getQueueId()), offsets);
// }
// }else {
// offsets=new ArrayList<OffsetNum>();
// offsets.add(new OffsetNum().setI(sendInfo.getMsgOffset()));
// queue2offsets=new HashMap<>();
// queue2offsets.put(String.valueOf(sendInfo.getQueueId()), offsets);
// topicAndFilter2queues.put(sendInfo.getTopicAndFilter().toString(), queue2offsets);
// }
// sendInfoMap.remove(entry.getKey());
// /*
// * 死信队列暂时先简单清空....................................
// */
// deadMessageQueue.clear();
// }else
{
reSendQueue.add(sendInfo.getMsgInfo());//加入重投队列
// logger.error(sendInfo.getMsgInfo().getMsg()+"加入重投队列");
recoverPool.execute(new Runnable(){
@Override
public void run() {
ArrayList<OffsetNum> offsets=null;
// TODO Auto-generated method stub
for(int i=0;i<Config.maxqueue;i++){
if(offsets==null){
offsets=arrayStore.recover(group.getTopicAndFilter().toString(), String.valueOf(i));
}else offsets.addAll(arrayStore.recover(group.getTopicAndFilter().toString(), String.valueOf(i)));
}
logger.error("内存充足,恢复重投"+offsets);
}
});
}
}else{//三次重投失败
logger.error("消息"+sendInfo.getMsgInfo().getMsg().getMsgId()+" 给集群"+group+" "+sendInfo.getReSendCount()+" 次重投失败");
sendInfoMap.remove(sendInfo.getMsgInfo().getMsgInfoId());
deadMessageQueue.add(sendInfo.getMsgInfo());//加入死信队列
}
}else{
}
}
logger.error("存储重投的offsets");
for(Map.Entry<String, Map<String,ArrayList<OffsetNum>>> queue2offsets:topicAndFilter2queues.entrySet()){
for(Map.Entry<String,ArrayList<OffsetNum>> offsets:queue2offsets.getValue().entrySet()){
arrayStore.store(offsets.getValue(), queue2offsets.getKey(), offsets.getKey());
}
}
}
},timeoutLimit+100,1000);
}
/**
* 重投
* @param reSendQueue
* @param consumers
* @param offset
*/
public void startReSend(){
//第一次开启重投时创建线程池
reSendPool = Executors.newFixedThreadPool(reSendPoolSize/*Runtime.getRuntime().availableProcessors()+2*/);
for(int i=0;i<reSendPoolSize;i++){
reSendPool.execute(new Runnable() {
@Override
public void run() {
MessageInfo msgInfo=null;
while(true){
// System.out.println("消费失败条数:"+consumeFailCount.get());
// System.out.println("开始重投,重投队列长度:"+reSendQueue.size());
try {
msgInfo=reSendQueue.take();
} catch (InterruptedException e) {
Thread.interrupted();
}
if(msgInfo==null) continue;
//重投给消费者
group.consumersBalance().writeAndFlush(msgInfo.getMsg());
//sendResult 重置
group.getSendInfoMap().get(msgInfo.getMsgInfoId()).reSend();
}//end while
}
});
}
}
}

View File

@@ -0,0 +1,129 @@
package com.alibaba.middleware.race.mom.broker.function;
import io.netty.channel.Channel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.middleware.race.mom.Broker;
import com.alibaba.middleware.race.mom.broker.group.ConsumerGroup;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
/**
* 存储成功监听器:force到磁盘成功,回调触发返回ack给生产者
* 一次存储过程,对应一个监听器
* @author youngforever
*
*/
public class StoreSucceedListener {
private static Logger logger = LoggerFactory.getLogger(StoreSucceedListener.class);
private static ExecutorService sendACKPool = Executors.newFixedThreadPool(1);
private Map<Channel/*producer*/,Integer/*msgIds*/> waitAckNumMap=new HashMap<>();
private static int i=0;
private Map<Channel/*producer*/,List<String/*msgId*/>> waitAckMap=new HashMap<>();
private Map<Channel/*producer*/,StringBuilder/*msgIds*/> waitAcksMap=new HashMap<>();
private Map<Channel/*producer*/,ArrayList<String>/*sendId or ack String*/> waitAckGroupMap=new HashMap<>();
// private StringBuilder acks=new StringBuilder();
/**
* 一次存储成功回调,存储完成(强行force)后异步返回对应的ack
*/
public void onStoreSucceed(TopicAndFilter topicAndFilter,int queueIndex,int offset){
/**
* ack返回
*/
sendACKPool.execute(new Runnable(){
@Override
public void run() {
// for(Channel producer:waitAckMap.keySet()){
// for(String msgId:waitAckMap.get(producer)){
// producer.writeAndFlush(msgId + "\r\n");
// i++;
//// System.out.println("存储成功,返回ack"+i+"条");
// }
// }
// for(Map.Entry<Channel,StringBuilder> acks:waitAcksMap.entrySet()){
// acks.getKey().writeAndFlush(acks.getValue().toString()+"\r\n");
// logger.error("sendback acks"+acks.getValue().toString());
// }
// for(Map.Entry<Channel,Integer>acks:waitAckNumMap.entrySet()){
// acks.getKey().writeAndFlush(acks.getValue()+"\r\n");
//// logger.error("sendback acks"+acks.getValue().toString());
// }
for(Map.Entry<Channel,ArrayList<String> >ack:waitAckGroupMap.entrySet()){
StringBuilder acks=new StringBuilder();
for(String id:ack.getValue())
{
acks.append("@");
acks.append(id);
}
ack.getKey().writeAndFlush(acks+"\r\n");
//System.out.println("返回的是:"+acks);
// logger.error("sendback acks"+acks.getValue().toString());
}
}
});
/**
* 精确发送已存储的消息
*/
ConcurrentHashMap<String, ConsumerGroup> needSendGroups=ConsumerGroup.getNeedSendGroups(topicAndFilter);
if(needSendGroups!=null)
for(ConsumerGroup consumerGroup:needSendGroups.values()){
// consumerGroup.startSend();
consumerGroup.sendSpecificMsgs(queueIndex, offset);
/**
* 存储到文件,再来设置MaxOffset
*/
consumerGroup.setMaxOffset( queueIndex,offset);
}
}
/**
* 添加ack等待
*/
public void addAckWaiter(Channel producer,String msgId){
List<String/*msgId*/> msgIds=waitAckMap.get(producer);
if(msgIds==null){
msgIds=new ArrayList<>();
msgIds.add(msgId);
waitAckMap.put(producer,msgIds);
}else {
msgIds.add(msgId);
}
}
public void addAckWaiterGroup(Channel producer,String msgId){
StringBuilder acks=waitAcksMap.get(producer);
if(acks==null){
acks=new StringBuilder();
acks.append(msgId).append(" ");
waitAcksMap.put(producer, acks);
}else acks.append(msgId).append(" ");
}
public void addAckWaiterNum(Channel producer){
Integer ackNum=waitAckNumMap.get(producer);
logger.debug(String.valueOf(ackNum));
if(ackNum==null){
ackNum=new Integer(1);
waitAckNumMap.put(producer, ackNum);
}else waitAckNumMap.put(producer, ++ackNum);
}
public void addAckGroupWaiter(Channel producer,ArrayList<String> sendId){
List<String> ack=waitAckGroupMap.get(producer);
logger.debug(String.valueOf(ack));
if(ack==null){
waitAckGroupMap.put(producer, sendId);
}else if(!ack.equals(sendId)){
logger.error(" 两次存储并未串行,可能需要解决异步调用");
}
}
}

View File

@@ -0,0 +1,44 @@
package com.alibaba.middleware.race.mom.broker.function;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.broker.group.ConsumerGroup;
import com.alibaba.middleware.race.mom.store.SubscribeStore;
import com.alibaba.middleware.race.mom.store.SubscribeStoreImp;
public class SubsStore {
private static Logger logger = LoggerFactory.getLogger(SubsStore.class);
private static SubscribeStore substore=new SubscribeStoreImp();
private static Timer timer=new Timer();
/**
* 定时任务-存储订阅关系
* @param start
* @param during
*/
public static void subscribeStoreStart(){
timer.schedule(new TimerTask(){
@Override
public void run() {
logger.error("异步-订阅关系/消费进度定时持久化任务");
ArrayList<Offset> sublist=new ArrayList<>();
for(ConcurrentHashMap<String/*groupid*/,ConsumerGroup/* group */> consumerGroups:ConsumerGroup.topicAndFilter2groups.values()){
for (ConsumerGroup consumerGroup :consumerGroups.values()){
//System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
sublist.addAll(consumerGroup.getConsumeOffsets());
}
}
substore.write(sublist);
logger.error("订阅消费进度关系刷盘"+sublist);
}
},1000, 1000);
}
}

View File

@@ -0,0 +1,534 @@
package com.alibaba.middleware.race.mom.broker.group;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.ConsumeResult;
import com.alibaba.middleware.race.mom.Message;
import com.alibaba.middleware.race.mom.SendStatus;
import com.alibaba.middleware.race.mom.broker.function.MessageInfo;
import com.alibaba.middleware.race.mom.broker.function.Offset;
import com.alibaba.middleware.race.mom.broker.function.SendInfo;
import com.alibaba.middleware.race.mom.broker.function.SendInfoScanner;
import com.alibaba.middleware.race.mom.config.Config;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
/**
* 消费者集群管理
* @author young
*
*/
/**
* 消费者集群管理
* @author young
*
*/
public class ConsumerGroup {
private static Logger logger = LoggerFactory.getLogger(ConsumerGroup.class);
/**
* 所有用于发送的 线程池可分配大小,也可以不限制大小,但也许应给避免订阅集群过多,发送线程池过大,不断优化测试.....
*/
private static int sendThreadPoolTotalSize=10;
/**
* 每个订阅集群
*/
private LinkedList<Channel>consumers = new LinkedList<Channel>();
private String groupId;
private String subscribedTopic;
private Map<String,String> subscribedFilter;
private TopicAndFilter topicAndFilter;
/**
* 每个集群的发送信息(发送状态,失败,成功,超时等)
*/
private Map<String/* msgId */, SendInfo> sendInfoMap = new ConcurrentHashMap<>();
/**
* 重投
*/
private SendInfoScanner sendInfoScanner=new SendInfoScanner(this);
// private Map<String/* topic@group */, LinkedList<Offset>> topicAndgroup2subScribe = new ConcurrentHashMap<>();
/*
* 每个集群的sendQueueNum个发送队列,对应消息拆分存储为sendQueueNum份文件
* sendThreadPoolSize为分配改当前集群发送线程池大小,不断优化测试.....
* sendPool,负责当前集群发送的线程池
*/
/**
* 发送队列个数,与存储队列一一对应,须全局统一配置(错了将报错,注意!!!!)
*/
private int sendQueueNum=Config.maxqueue;
// private int sendThreadPoolSize=sendQueueNum*4;
private int sendThreadPoolSize=Runtime.getRuntime().availableProcessors()/2;
private LinkedList<BlockingQueue<MessageInfo/* TopicAndFilter+msgOffset */>> sendQueues = new LinkedList<>();
/**
* 当前集群(组)的消费进度情况
*/
private LinkedList<Offset> consumeOffsets=new LinkedList<Offset> ();
private int sendQueueBalancer=-1;
private ExecutorService sendPool = Executors.newFixedThreadPool(sendThreadPoolSize);
/**
* 构造函数
* @param subscribedTopic
* @param subscribedFilter
* @param groupId
*/
public ConsumerGroup(String subscribedTopic,Map<String,String> subscribedFilter,String groupId){
this.subscribedTopic=subscribedTopic;
this.subscribedFilter=subscribedFilter;
topicAndFilter=new TopicAndFilter(subscribedTopic,subscribedFilter);
this.groupId=groupId;
/*
* 集群创建时初始化队列,初始化对应的offet进度
*/
Offset offset;
for(int i=0;i<sendQueueNum;i++){
this.sendQueues.add(new LinkedBlockingQueue<MessageInfo>());
// offset=new Offset(subscribedTopic,groupId,topicAndFilter.toString());
offset=new Offset();
offset.setQueueIndex(i);
// offset.setTopic(subscribedTopic);
this.consumeOffsets.add(offset);
}
/*
* 启动发送任务,不采用立即转发方式,旺旺群讨论的结果
*/
// startSend();
/*
* 启动重投检测
*/
// sendInfoScanner.start();
}
/**
* 负载均衡,且去除死掉的消费者
* @return 本次发往的消费者.如果集群都不在线,则返回null
*/
private volatile int consumerBalancer=-1;
public synchronized Channel consumersBalance(){
consumerBalancer++;
if(consumerBalancer==consumers.size()){
consumerBalancer=0;
}
Channel consumer=consumers.get(consumerBalancer);
if (consumer==null) return null;
if(!consumer.isOpen()){
logger.error("消费者失去连接: " + consumer.hashCode());
consumers.remove(consumer);
return consumersBalance();
}else return consumer;
}
/**
* 发送队列均衡
* @return
*/
public synchronized BlockingQueue<MessageInfo> sendQueuesBalance(){
sendQueueBalancer++;
if(sendQueueBalancer==sendQueueNum){
sendQueueBalancer=0;
}
BlockingQueue<MessageInfo> sendQueue=sendQueues.get(sendQueueBalancer);
return sendQueue;
}
/**
* 开始发送任务,此方式为收到消息,立即转发,与存储并行
*/
public void startSend(){
for(final BlockingQueue<MessageInfo> sendQueue:sendQueues){
for(int i=0;i<sendThreadPoolSize/sendQueueNum;i++){//每个队列提交几次任务,占满线程池
sendPool.execute(new Runnable(){
MessageInfo msgInfo;
Message msg;
Channel consumer;
final int queueIndex=sendQueues.indexOf(sendQueue);
@Override
public void run() {
while(true){
while(!sendQueue.isEmpty()){
// try {
// msgInfo=sendQueue.take();
msgInfo=sendQueue.poll();
// System.out.println(sendQueue.size());
// } catch (InterruptedException e) {
// 不可能出现线程中断异常的
// Thread.interrupted();//清除中断状态
// }
//取消息,发送
if(msgInfo==null) break;
msg=msgInfo.getMsg();
// if(msg==null) continue;
if(msg==null) break;
consumer=consumersBalance();
//记录发送状态信息
SendInfo sendInfo=new SendInfo(msgInfo);
sendInfo.setTopicAndFilter(topicAndFilter);
sendInfo.setSendTime(System.currentTimeMillis());
sendInfoMap.put(sendInfo.getTopicAndFilter().toString()+String.valueOf(sendInfo.getMsgOffset()),sendInfo);
if(consumer!=null){
consumer.writeAndFlush(msg);
sendInfo.setStatus(SendStatus.SEND);
}else {
logger.error("消费者集群都不在线,须集群恢复后重投");
sendInfo.setStatus(SendStatus.GROUPLOST);
}
}
}
}
});
}
}
}
/**
* 发送当前集群 某一队列 特定offset范围的消息
* 此方式 为成功存储再转发
* @param queueIndex
* @param num 存出成功可发送条数
*/
public void sendSpecificMsgs(final int queueIndex,final int num){
sendPool.execute(new Runnable(){
@Override
public void run() {
int i=0;
Channel consumer;
MessageInfo msgInfo;
Message msg;
do{
msgInfo=sendQueues.get(queueIndex).poll();
if(msgInfo==null) break;
msg=msgInfo.getMsg();
if(msg==null) break;
consumer=consumersBalance();
consumer.writeAndFlush(msg);
logger.debug("send msg:"+msg);
SendInfo sendInfo=new SendInfo(msgInfo);
sendInfo.setTopicAndFilter(topicAndFilter);
sendInfo.setSendTime(System.currentTimeMillis());
sendInfoMap.put(sendInfo.getMsgInfo().getMsgInfoId(),sendInfo);
}while(++i<=num);
}
});
}
/**
* 设置队列的最大存储进度
* @param queueIndex
* @param maxOffset
*/
public void setMaxOffset( int queueIndex, int maxOffset){
consumeOffsets.get(queueIndex).setMaxOffset(maxOffset);
}
public void handleConsumeResult(SendInfo sendInfo, ChannelHandlerContext ctx) {
logger.error("result handle");
String msgId = sendInfo.getTopicAndFilter().toString()+String.valueOf(sendInfo.getMsgOffset());
/*
* 进度仅仅在此处收到ack 更新.无论成功或失败超时(进入重试队列)
* 假设此处未收到未更新进度,而超时扫描 到超时进入重试队列(即重试队列中消息对应offset大于此处更新的currentoffset,则必然此处currentoffset开始发生连续超时)
* 连续超时 将不会更新到重试 随offset表(队列)更新到 重试进度,如果故障broker重启将由此处currentoffset开始 连续恢复
*/
// topicAndgroup2subScribe.get(topic+"@"+groupId).get(sendInfo.getQueueId()).setCurrentoffset((sendInfo.getMsgOffset()));
/**
* 当前集群投递成功
*/
if((!sendInfo.isTimeout())&&sendInfo.getStatus().equals(SendStatus.SUCCESS)){//未超时并且消费成功
consumeOffsets.get(sendInfo.getQueueId()).setCurrentoffset(sendInfo.getMsgOffset());
if(sendInfo.getReSendCount()!=0){
logger.error("消息"+sendInfo.getMsgInfo().getMsg()+" 给集群"+this+" "+sendInfo.getReSendCount()+" 次重新投递成功");
}else {
System.out.println("消息"+sendInfo.getMsgInfo().getMsg()+" 给集群"+this+" "+sendInfo.getReSendCount()+" 次重新投递成功");
logger.error("消息"+sendInfo.getMsgInfo().getMsgInfoId()+"一次投递消费成功");
}
sendInfoMap.remove(sendInfo.getMsgInfo().getMsgInfoId());
// logger.error("sendInfoMap size:"+sendInfoMap.size());
}else if(sendInfo.getStatus().equals(SendStatus.FAIL)){//消费失败
consumeOffsets.get(sendInfo.getQueueId()).setCurrentoffset(sendInfo.getMsgOffset());
// logger.error("消费失败"+consumeFailCount.incrementAndGet()+"条");
}else if(sendInfo.isTimeout()){//消费超时,这个很有可能已经被超时扫描 给处理了,多久了才发过来
if(sendInfoMap.containsKey(msgId)){//因为有可能已经被超时扫描 给处理了
sendInfoMap.get(msgId).setStatus(SendStatus.TIMEOUT);
//这里其实 由超时扫描来处理就好
}
// logger.error("消费超时"+consumeTimeoutCount.incrementAndGet()+"条");
}
}
/**
* 加入发送队列,queueId(queueIndex)将由存储队列均衡后的index来决定,保证了sendQueue与storeQueue的一致性,从而保证文件索引与消费进度offset的精确对应
* @param offset
* @param msgInfo
*/
public void addToSendQueue(TopicAndFilter topicAndFilter/* */,MessageInfo msgInfo){
// this.sendQueuesBalance().add(offset);
//获取队列和对应的Offset
sendQueues.get(msgInfo.getQueueIndex()).add(msgInfo);
Offset offset=consumeOffsets.get(msgInfo.getQueueIndex());
// if(offset.getTopicAndFilter()==null){
// offset.setTopicAndFilter(topicAndFilter);
// }
if(offset.getTopic()==null){
offset.setTopic(topicAndFilter.getTopic());
offset.setFilter(topicAndFilter.getFilter());
}
}
public void addConsumer(Channel channel){
if(!consumers.contains(channel)){
consumers.add(channel);
}
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public LinkedList<Offset> getConsumeOffsets() {
return consumeOffsets;
}
public String getSubscribedTopic() {
return subscribedTopic;
}
public void setSubscribedTopic(String subscribedTopic) {
this.subscribedTopic = subscribedTopic;
}
public Map<String, String> getSubscribedFilter() {
return subscribedFilter;
}
public Map<String, SendInfo> getSendInfoMap() {
return sendInfoMap;
}
public void setSendInfoMap(Map<String, SendInfo> sendInfoMap) {
this.sendInfoMap = sendInfoMap;
}
public void setSubscribedFilter(Map<String, String> subscribedFilter) {
this.subscribedFilter = subscribedFilter;
}
public LinkedList<Channel> getConsumers() {
return consumers;
}
public void setConsumers(LinkedList<Channel> consumers) {
this.consumers = consumers;
}
public int getSendQueueNum() {
return sendQueueNum;
}
public void setSendQueueNum(int sendQueueNum) {
this.sendQueueNum = sendQueueNum;
}
public LinkedList<BlockingQueue<MessageInfo>> getSendQueues() {
return sendQueues;
}
public void setSendQueues(LinkedList<BlockingQueue<MessageInfo>> sendQueues) {
this.sendQueues = sendQueues;
}
public int getSendQueueBalancer() {
return sendQueueBalancer;
}
public TopicAndFilter getTopicAndFilter() {
return topicAndFilter;
}
public void setTopicAndFilter(TopicAndFilter topicAndFilter) {
this.topicAndFilter = topicAndFilter;
}
public void setSendQueueBalancer(int sendQueueBalancer) {
this.sendQueueBalancer = sendQueueBalancer;
}
public String toString(){
return "subscribedTopic"+subscribedTopic+" subscribedFilter"+subscribedFilter;
}
/**
* 非静态部分 为某一具体集群
* 静态部分 属于集群组,管理所有订阅集群
*/
/**
* 订阅集群组,每种topicAndfilter可能有一个或多个订阅集群
*/
public static Map<String/* topicAndfilter */, ConcurrentHashMap<String/*groupid*/,ConsumerGroup/* group */>> topicAndFilter2groups = new ConcurrentHashMap<>();
/**
* 添加 topicAndFilter的订阅集群
* @param topicAndFilter
* @param groupId
*/
public static ConsumerGroup addGroup(TopicAndFilter topicAndFilter,String groupId){
Map<String,ConsumerGroup> groups=topicAndFilter2groups.get(topicAndFilter.toString());//集群组
ConsumerGroup group=new ConsumerGroup(topicAndFilter.getTopic(),topicAndFilter.getFilter(),groupId);
if(groups==null){
groups=new ConcurrentHashMap<String,ConsumerGroup>();
groups.put(groupId,group);
topicAndFilter2groups.put(topicAndFilter.toString(), (ConcurrentHashMap<String, ConsumerGroup>) groups);
}else if(!groups.containsKey(groupId)){
groups.put(groupId, group);
}
// else {//集群已经存在,这种情况可能发生在集群全部掉线,而后恢复重连.或者集群新增消费者
// group=groups.get(groupId);
// }
return group;
}
public static ConcurrentHashMap<String,ConsumerGroup> getGroups(TopicAndFilter topicAndFilter){
return topicAndFilter2groups.get(topicAndFilter.toString());
}
public static ConsumerGroup getGroup(TopicAndFilter topicAndFilter,String groupId){
Map<String,ConsumerGroup> groups=getGroups(topicAndFilter);
Map<String,ConsumerGroup> groupsNoFilter=getGroups(new TopicAndFilter(topicAndFilter.getTopic(),null));
ConsumerGroup group;
if(groupsNoFilter==null&&groups==null){
return null;
}else if(groups!=null&&(group=groups.get(groupId))!=null){
return group;
}else if(groupsNoFilter!=null){
return groupsNoFilter.get(groupId);
}else return null;
}
/**
* 取得filter 和null两种needSend订阅集群组
* @param topicAndFilter
* @return
*/
public static ConcurrentHashMap<String,ConsumerGroup> getNeedSendGroups(TopicAndFilter topicAndFilter){
ConcurrentHashMap<String,ConsumerGroup> groups=getGroups(topicAndFilter);
TopicAndFilter topicNoFilter=new TopicAndFilter (topicAndFilter.getTopic(),null);
ConcurrentHashMap<String,ConsumerGroup> noFilterGroups=getGroups(topicNoFilter);
if(groups!=null&&noFilterGroups!=null){
groups.putAll(getGroups(topicNoFilter));
}else if(noFilterGroups!=null){
groups=noFilterGroups;
}
// if(groups!=null)
// for(ConsumerGroup group:groups.values()){
// if(group.consumers.isEmpty()){
// groups.remove(group.getGroupId());
// }
// }
return groups;
}
/**
* 取得 此topicAndFilter下所有负载均衡后须发送的消费者
* @param topicAndFilter
* @return
*/
public static LinkedList<Channel> getNeedSendBalancedConsumers(TopicAndFilter topicAndFilter){
LinkedList<Channel> needSendBalancedConsumers=new LinkedList<Channel>();
Map<String,ConsumerGroup>groups=getNeedSendGroups(topicAndFilter);
for(ConsumerGroup consumerGroup:groups.values()){//每个须发送集群都要负载均衡找出消费者
Channel consumer=consumerGroup.consumersBalance();
if(consumer!=null){
needSendBalancedConsumers.add(consumer);
}else {
logger.error("消费者集群"+consumerGroup+"全部失去连接");
}
}
return needSendBalancedConsumers;
}
public static int needSendGroupsNum(TopicAndFilter topicAndFilter){
return getNeedSendGroups(topicAndFilter).size();
}
// public static boolean contains(TopicAndFilter topicAndFilter){
// return topicAndFilter2groups.containsKey(topicAndFilter.toString());
// }
/**
* 注册订阅者(消费者)
* @param consumer
* @param groupId
* @param topicAndFilter
*/
public static void addConsumer(Channel consumer ,String groupId,TopicAndFilter topicAndFilter){
ConsumerGroup group=getGroup(topicAndFilter,groupId);
if(group!=null){
if(group.consumers.size()==0){
logger.error("消费者集群全部down机后恢复,触发消费者离线重投");
/**
* TO DO..........................................................
*/
}
group.addConsumer(consumer);
}else addGroup(topicAndFilter,groupId).addConsumer(consumer);
}
/**
* 消费结果总处理
* @param consumeResult
* @param ctx
*/
public static void confirmConsumer(ConsumeResult consumeResult, ChannelHandlerContext ctx){
logger.debug("recv consume result");
String msgId = consumeResult.getMsgId();
ConsumerGroup group=ConsumerGroup.getGroup(consumeResult.getTopicAndFilter(),consumeResult.getGroupId());
SendInfo sendInfo=group.sendInfoMap.get(msgId);
if(sendInfo==null) return;
switch (consumeResult.getStatus()){
case SUCCESS:sendInfo.setStatus( SendStatus.SUCCESS); break;
case FAIL:sendInfo.setStatus( SendStatus.FAIL); break;
default:logger.error("消费者 无消费状态.......");break;
}
group.handleConsumeResult(sendInfo, ctx);
}
/**
* 准备消息发送(进入发送队列),存储完成后发送
* @param topicAndFilter
* @param msgInfo
*/
private static long waitSubStartTime;
public static void sendMsg(TopicAndFilter topicAndFilter,MessageInfo msgInfo){
//获取消息应给发往的订阅集群组,即所有订阅此消息的集群
Map<String,ConsumerGroup> groups=ConsumerGroup.getNeedSendGroups(topicAndFilter);
if(groups==null){
if(waitSubStartTime==0){
waitSubStartTime=System.currentTimeMillis();
}else if(System.currentTimeMillis()-waitSubStartTime>Config.noConsumerWaitTimeLimit){//800ms后仍无订阅者信息,则递归结束,
msgInfo.getProducer().writeAndFlush("fail@"+msgInfo.getMsg().getMsgId()+ "\r\n");
logger.error(Config.noConsumerWaitTimeLimit+"ms 任无此"+topicAndFilter+"的订阅集群(组)发起订阅");
return;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//logger.error("没有此"+topicAndFilter+"的订阅集群(组)");
sendMsg(topicAndFilter,msgInfo);//递归不断尝试获取订阅者集群
}else{
//设置需要发送的订阅集群数
// msgInfo.setSubGroupsCount(groups.size());
//加入各订阅集群的发送队列,自动发送给消费者
logger.debug((System.currentTimeMillis()-waitSubStartTime)+"发现订阅信息");
for(ConsumerGroup consumerGroup:groups.values()){
consumerGroup.addToSendQueue(topicAndFilter,msgInfo);
}
}
waitSubStartTime=0;
}
// /**
// * 以groupId区分俩个组
// */
// @Override
// public boolean equals(Object obj) {
// if(obj instanceof ConsumerGroup){
// if(((ConsumerGroup) obj).getGroupId().equals(this.groupId))return true;
// else return false;
// }else return false;
// }
}

View File

@@ -0,0 +1,226 @@
package com.alibaba.middleware.race.mom.broker.group;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.middleware.race.mom.broker.function.MessageInfo;
import com.alibaba.middleware.race.mom.broker.function.MessageInfoQueue;
import com.alibaba.middleware.race.mom.broker.function.MessageSend;
import com.alibaba.middleware.race.mom.broker.function.MessageStore;
import com.alibaba.middleware.race.mom.util.TopicAndFilter;
/**
* 生产者集群(组)管理
* 假设存在多个集群生产同一种topicAndfilter的消息,broker端可将集群组视为同一集群,不做集群区分,只以topicAndfilter区分
* 消息存储以topicAndfilter将生产者消息归类存储
* ack返回,我们假定必须返回相应生产者(消息的直接生产者),而不是集群中任一生产者
*
* @author youngforever
*/
public class ProducerGroup {
private static Logger logger = LoggerFactory.getLogger(ProducerGroup.class);
/**
* 每个生产者集群
*/
// private Map<String,/*producerId*/Channel/*producer*/>producers = new HashMap<>();
// private String groupId;
// private String produceTopic;
// private Map<String,String> produceFilter;
private TopicAndFilter produceTopicAndFilter;
private MessageStore msgStore ;
/**
* 私有构造函数,仅用于恢复时
* @param produceTopic
* @param produceFilter
* @param queueMaxOffsets
*/
private ProducerGroup(TopicAndFilter topicAndFilter,Map<Integer /*queueIndex*/,Integer/*maxOffset*/> queueMaxOffsets){
this.produceTopicAndFilter=topicAndFilter;
this.msgStore=new MessageStore(produceTopicAndFilter, queueMaxOffsets);
}
/**
* 用于新增生产者集群
* @param produceTopic
* @param produceFilter
* @param queueMaxOffsets
*/
public ProducerGroup(String produceTopic,Map<String,String> produceFilter){
// this.produceTopic=produceTopic;
// this.produceFilter=produceFilter;
this.produceTopicAndFilter=new TopicAndFilter(produceTopic,produceFilter);
this.msgStore=new MessageStore(produceTopicAndFilter);
}
// public void addProducer(Channel producer,String producerId){
// if(!producers.containsKey(producerId)){
// producers.put(producerId,producer);
// }else if(!producers.get(producerId).isOpen()){//已经存在此id 的producer,但是关闭了连接. 现在应该时发起了重连
// producers.put(producerId,producer);
// }
// }
public String toString(){
return produceTopicAndFilter.toString();
}
/**
* 非静态部分 为某一具体集群
* 静态部分 属于集群组,管理所有生产者集群
*/
public static Map<String/* topicAndfilter */, ProducerGroup/* group */> topicAndFilter2group = new ConcurrentHashMap<>();
/**
* 添加 topicAndFilter的订阅集群
* @param topicAndFilter
* @param groupId
*/
public static ProducerGroup addGroup(TopicAndFilter topicAndFilter){
ProducerGroup group=topicAndFilter2group.get(topicAndFilter.toString());//集群组
if(group==null){
group=new ProducerGroup(topicAndFilter.getTopic(),topicAndFilter.getFilter());
topicAndFilter2group.put(topicAndFilter.toString(),group);
}
return group;
}
/**
* 仅用于恢复时
* @param topicAndFilter
* @param queueMaxOffsets
* @return
*/
private static ProducerGroup addGroup(TopicAndFilter topicAndFilter,Map<Integer /*queueIndex*/,Integer/*maxOffset*/> queueMaxOffsets){
ProducerGroup group=topicAndFilter2group.get(topicAndFilter.toString());//集群组
if(group==null){
group=new ProducerGroup(topicAndFilter,queueMaxOffsets);
topicAndFilter2group.put(topicAndFilter.toString(),group);
}
return group;
}
public static ProducerGroup getGroup(TopicAndFilter topicAndFilter){
return topicAndFilter2group.get(topicAndFilter.toString());
}
/**
* 注册生产者
* @param producer
* @param groupId
* @param topicAndFilter
*/
/*
* 采用了 存储成功监听器机制,那么生产者实际上不用保存
*/
// public static void addProducer(Channel producer ,String producerId,String producerGroupId,TopicAndFilter topicAndFilter){
// ProducerGroup group=getGroup(topicAndFilter);
// if(group!=null){
// group.addProducer(producer,producerId);
// }else addGroup(topicAndFilter).addProducer(producer,producerId);
//// System.out.println(topicAndFilter2groups);
// }
/**
*
* @param topicAndFilter
* @param msgInfo
* @return offset,消息进入持久化队列后,返回下标做为offset(代表存储顺序,对应文件消息索引,同时用于表示消费进度)
*/
// public static String storeMsg(TopicAndFilter topicAndFilter,MessageInfo msgInfo){
// ProducerGroup producerGroup = getGroup(topicAndFilter);
// if(producerGroup==null){
// logger.error("生产者集群(组)尚未注册");
// producerGroup=addGroup(topicAndFilter);
// }
// return producerGroup.msgStore.storeMsg(msgInfo);
// }
/**
* 组存处理
* @param topicAndFilter
* @param msgInfo
* @return offset返回为maxOffset,消息进入持久化队列后,返回下标做为offset(代表存储顺序,对应文件消息索引,同时用于表示消费进度)
*/
public static String storeMsg(TopicAndFilter topicAndFilter,MessageSend msgSend){
ProducerGroup producerGroup = getGroup(topicAndFilter);
if(producerGroup==null){
logger.error("生产者集群(组)尚未注册");
producerGroup=addGroup(topicAndFilter);
}
return producerGroup.msgStore.storeMsg(msgSend);
}
/**
* 恢复
*/
public static void recover(HashMap<TopicAndFilter/*TopicAndFilter*/,Map<Integer /*queueIndex*/,Integer/*maxOffset*/>>producerGroupRecoverInfos){
for(Map.Entry<TopicAndFilter,Map<Integer /*queueIndex*/,Integer/*maxOffset*/>>queueMaxOffsets :producerGroupRecoverInfos.entrySet()){
addGroup(queueMaxOffsets.getKey(),queueMaxOffsets.getValue());
System.out.println(addGroup(queueMaxOffsets.getKey(),queueMaxOffsets.getValue()));
}
}
/**
* 集群组.区分集群(先勿删!!!)
*/
// /**
// * 订阅集群组,每种topicAndfilter可能有一个或多个订阅集群
// */
// public static Map<String/* topicAndfilter */, ConcurrentHashMap<String/*groupid*/,ProducerGroup/* group */>> topicAndFilter2groups = new ConcurrentHashMap<>();
// /**
// * 添加 topicAndFilter的订阅集群
// * @param topicAndFilter
// * @param groupId
// */
// public static ProducerGroup addGroup(TopicAndFilter topicAndFilter,String groupId){
// Map<String,ProducerGroup> groups=topicAndFilter2groups.get(topicAndFilter.toString());//集群组
// ProducerGroup group=new ProducerGroup(topicAndFilter.getTopic(),topicAndFilter.getFilter(),groupId);
// if(groups==null){
// groups=new ConcurrentHashMap<String,ProducerGroup>();
// groups.put(groupId,group);
// topicAndFilter2groups.put(topicAndFilter.toString(), (ConcurrentHashMap<String, ProducerGroup>) groups);
// }else if(!groups.containsKey(groupId)){
// groups.put(groupId, group);
// }
// return group;
// }
// public static ConcurrentHashMap<String,ProducerGroup> getGroups(TopicAndFilter topicAndFilter){
// return topicAndFilter2groups.get(topicAndFilter.toString());
// }
// public static ProducerGroup getGroup(TopicAndFilter topicAndFilter,String groupId){
// Map<String,ProducerGroup> groups=getGroups(topicAndFilter);
// if(groups!=null){
// return groups.get(groupId);
// }else return null;
// }
// /**
// * 注册生产者
// * @param producer
// * @param groupId
// * @param topicAndFilter
// */
// public static void addProducer(Channel producer ,String producerId,String producerGroupId,TopicAndFilter topicAndFilter){
// ProducerGroup group=getGroup(topicAndFilter,producerGroupId);
// if(group!=null){
// group.addProducer(producer,producerId);
// }else addGroup(topicAndFilter,producerGroupId).addProducer(producer,producerId);
// System.out.println(topicAndFilter2groups);
// }
// public static void storeMsg(TopicAndFilter topicAndFilter,MessageInfo msgInfo){
// ProducerGroup producerGroup = getGroup(topicAndFilter,msgInfo.getProducerGroupId());
// if(producerGroup!=null){
// producerGroup.msgStoreHanler.storeCache.
// }else{
// logger.error("生产者集群尚未注册");
// }
// }
// /**
// * 以groupId区分俩个集群
// */
// @Override
// public boolean equals(Object obj) {
// if(obj instanceof ProducerGroup){
// if(((ProducerGroup) obj).getGroupId().equals(this.groupId))return true;
// else return false;
// }else return false;
// }
}

View File

@@ -0,0 +1,28 @@
package com.alibaba.middleware.race.mom.config;
public class Config {
//每个group对应的队列条数
public static int maxqueue=1;
//内存每个队列只能装这么多条消息
public static int maxMsgNum=30000/maxqueue;
//每次从磁盘拉取多少条
public static int maxLoadNum=2000;
/**
* 重投次数限制
* 达到配置次数仍然失败,则不再重投
*/
public static int maxReSendTime=3;
/**
* 10s超时限制
*/
public static int timeoutLimit=10000;
/**
* 磁盘拉因子,当内存使用达到虚拟机内存(-Xms配置的memoryFullFactor倍时消息不能再存入内存从磁盘拉取
*/
public static double memoryFullFactor=0.25;
/**
* 无消费者时重复尝试时间 ms,可能系统启动时,订阅信息稍有延迟
*/
public static int noConsumerWaitTimeLimit=500;
}

View File

@@ -0,0 +1,59 @@
package com.alibaba.middleware.race.mom.serializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class JdkObjectSerializer{
public <T> T deserialize( final byte[] bytes , final Class<T> clazz ) {
final ByteArrayInputStream in = new ByteArrayInputStream( bytes );
try {
final ObjectInputStream ois = new ObjectInputStream( in );
Object obj = ois.readObject();
return clazz.cast( obj );
}
catch ( final ClassNotFoundException e ) {
throw new IllegalStateException( e.getMessage() , e );
}
catch ( final IOException e ) {
throw new IllegalStateException( e.getMessage() , e );
}
finally {
try {
in.close();
}
catch ( final IOException e ) {
throw new IllegalStateException( e.getMessage() , e );
}
}
}
public <T> byte[] serialize( final T source ) {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
final ObjectOutputStream oos = new ObjectOutputStream( out );
oos.writeObject( source );
oos.flush();
}
catch ( final IOException e ) {
throw new IllegalStateException( e.getMessage() , e );
}
finally {
try {
out.close();
}
catch ( final IOException e ) {
throw new IllegalStateException( e.getMessage() , e );
}
}
return out.toByteArray();
}
}

View File

@@ -0,0 +1,59 @@
package com.alibaba.middleware.race.mom.serializer;
import java.lang.reflect.Constructor;
import java.util.concurrent.ConcurrentHashMap;
import sun.reflect.ReflectionFactory;
import com.esotericsoftware.kryo.Kryo;
public class KryoxSerializer extends Kryo {
private final ReflectionFactory REFLECTION_FACTORY = ReflectionFactory
.getReflectionFactory();
private final ConcurrentHashMap<Class<?>, Constructor<?>> _constructors = new ConcurrentHashMap<Class<?>, Constructor<?>>();
@Override
public <T> T newInstance(Class<T> type) {
try {
return super.newInstance(type);
} catch (Exception e) {
return (T) newInstanceFromReflectionFactory(type);
}
}
private Object newInstanceFrom(Constructor<?> constructor) {
try {
return constructor.newInstance();
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public <T> T newInstanceFromReflectionFactory(Class<T> type) {
Constructor<?> constructor = _constructors.get(type);
if (constructor == null) {
constructor = newConstructorForSerialization(type);
Constructor<?> saved = _constructors.putIfAbsent(type, constructor);
if(saved!=null)
constructor=saved;
}
return (T) newInstanceFrom(constructor);
}
private <T> Constructor<?> newConstructorForSerialization(
Class<T> type) {
try {
Constructor<?> constructor = REFLECTION_FACTORY
.newConstructorForSerialization(type,
Object.class.getDeclaredConstructor());
constructor.setAccessible(true);
return constructor;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,48 @@
package com.alibaba.middleware.race.mom.serializer;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.List;
import org.nustaq.serialization.FSTConfiguration;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.serializers.JavaSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
public class RpcDecoder extends ByteToMessageDecoder {
private FSTConfiguration fst=FSTConfiguration.getDefaultConfiguration();
@Override
public final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
try{
if (in.readableBytes() < 4) {
return;
}
in.markReaderIndex();
int dataLength = in.readInt();
if (dataLength < 0) {
ctx.close();
}
if (in.readableBytes() < dataLength) {
in.resetReaderIndex();
return ;
}
byte[] data = new byte[dataLength];
in.readBytes(data);
out.add(fst.asObject(data));
}catch(Exception e)
{
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,48 @@
package com.alibaba.middleware.race.mom.serializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
import org.nustaq.serialization.FSTConfiguration;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.JavaSerializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.CharsetUtil;
public class RpcEncoder extends MessageToByteEncoder {
private FSTConfiguration fst=FSTConfiguration.getDefaultConfiguration();
public RpcEncoder() {
}
@Override
public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
try{
//对象
if (!String.class.isInstance(in)) {
byte[] data =fst.asByteArray(in);
//写入内容
out.writeInt(data.length);
out.writeBytes(data);
}
//字符串
else
{
String data=in.toString();
out.writeBytes(data.getBytes());
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,32 @@
package com.alibaba.middleware.race.mom.store;
import java.util.ArrayList;
/**
* 数组存储与恢复
* @param <OffsetNum>
*
*/
public interface ArrayStore {
/**
* 数组存储
* 每次调用以更新的方式(不能追加)
* @param offsets 需要存储的OffsetNum [] 一般用Integer[]存储OffsetNum [] 中所有条目
* @param topicAndFilter 这几个参数用于文件夹结构和消息存储一样去掉了consumerid项
* @param groupId
* @param queueId
*/
public boolean store(ArrayList<OffsetNum> arrayList,String topicAndFilter, String queueId);
/**
* 数组恢复
* @param topicAndFilter 这几个参数用于文件夹结构和消息存储一样去掉了consumerid项
* @param groupId
* @param queueId
* @return OffsetNum [],读出所有条目,并装到 OffsetNum []一般用Integer[])返回
*/
public ArrayList<OffsetNum> recover(String topicAndFilter, String queueId);
}

View File

@@ -0,0 +1,55 @@
package com.alibaba.middleware.race.mom.store;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
public class ArrayStoreImp implements ArrayStore {
private static String filePath = StoreConfig.baseDir + StoreConfig.arrayDir;
private static Logger logger = LoggerFactory.getLogger(ArrayStoreImp.class);
private static ConcurrentHashMap<String, FileStoreManager> fileStoreManagerMap = new ConcurrentHashMap<String, FileStoreManager>();
@Override
public boolean store(ArrayList<OffsetNum> arrayList, String topicAndFilter,
String queueId) {
// TODO Auto-generated method stub
// 对应的文件管理器
String arrayFilePath = filePath + "/" + topicAndFilter+"/"+queueId;
FileStoreManager fileStoreManager = fileStoreManagerMap
.get(arrayFilePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(arrayFilePath);
// 为恢复
fileStoreManagerMap.put(arrayFilePath, fileStoreManager);
}
// 将写位置重置为16
fileStoreManager.resetFilePosition();
ArrayList<byte[]> dataList = new ArrayList<byte[]>(arrayList.size());
int count = 1;
for (OffsetNum tmp : arrayList) {
logger.debug("保存订阅关系 i+== " + (count++) + " , " + tmp.i);
dataList.add(JSON.toJSONBytes(tmp));
}
return fileStoreManager.saveMessage(dataList);
}
@Override
public ArrayList<OffsetNum> recover(String topicAndFilter, String queueId) {
String arrayFilePath = filePath + "/" + topicAndFilter+"/"+queueId;
FileStoreManager fileStoreManager = fileStoreManagerMap
.get(arrayFilePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(arrayFilePath);
// 为恢复
fileStoreManagerMap.put(arrayFilePath, fileStoreManager);
}
return (ArrayList<OffsetNum>) fileStoreManager.getOffsetNum();
}
}

View File

@@ -0,0 +1,40 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Comm {
/**
* 获取每个文件的名称地址
*
*/
private static Logger logger = LoggerFactory
.getLogger(Comm.class);
public static ArrayList<Integer> getFileNum(String filePath) {
ArrayList<Integer> fileNumArray=new ArrayList<Integer>();
logger.error("filePath==="+filePath);
File indexFile = new File(filePath);
if (indexFile.isDirectory()) {
String[] fileList = indexFile.list();
int fileCount = fileList.length;
if (fileCount == 0) {
logger.warn(" 没有 index file 存在!");
} else {
// 遍历文件编号并保存
for (int i = 0; i < fileCount; i++) {
int t = Integer.parseInt(fileList[i]);
fileNumArray.add(t);
logger.error(" 查找index目录下的所有文件并记录为一个数组中 fileList[i]= "+fileList[i]);
}
}
Collections.sort(fileNumArray);
}
return fileNumArray;
}
}

View File

@@ -0,0 +1,446 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DataMappedFile {
// 文件编号
private long dataNum;
// 文件大小
private long fileSize;
// 文件数目
private long fileCount = 0;
// data文件
private MappedFileInfo dataMappedFile;
// 文件的fileChannel
private FileChannel fileChannel;
// 文件的MappedByteBuffer
private MappedByteBuffer mappedByteBuffer;
// 文件夹的路径
private String filePath;
private static Logger logger = LoggerFactory
.getLogger(DataMappedFile.class);
// 保存已经打开的读文件列表
private static ConcurrentHashMap<String, MappedFileInfo> readDataFileMap = new ConcurrentHashMap<String, MappedFileInfo>();
public long dataWriterPositon;
/**
* 构造函数
*
* @param filePath
*/
public DataMappedFile(String filePath) {
this.filePath = filePath;
this.initFileInfo();
/*
* this.mappedByteBuffer = this.dataMappedFile.getMappedByteBuffer();
* this.fileChannel = this.dataMappedFile.getFileChannel();
*/
}
/**
* 把数据从data文件的读出 带msg大小的标识
*
* @param Offset
* 在data文件中的位置
* @param size
* 写入data文件中数据的大小
* @param dataFileNum
* 写入data文件的名称
* @return
*
*/
public List<long[]> checkLastMsg(long[] indexData) {
// 保存已经开打的再读data文件
List<long[]> rs = new ArrayList<long[]>();
int offset, size, dataFileNum;
if (indexData == null) {
// 初始状态index文件没有数据
logger.error("indexData == null");
dataFileNum = 0;
offset = 16;
size = 0;
logger.error(" int offset, int size, int dataFileNum=" + offset
+ " " + size + " " + dataFileNum);
} else {
offset = (int) indexData[0];
size = (int) indexData[1];
dataFileNum = (int) indexData[2];
logger.error("int offset, int size, int dataFileNum=" + offset
+ " " + size + " " + dataFileNum);
}
MappedFileInfo readForDataFile = readDataFileMap.get(this.filePath
+ "/" + dataFileNum);
if (readForDataFile == null) {
readForDataFile = new MappedFileInfo(this.filePath + "/"
+ dataFileNum);
readDataFileMap.put(this.filePath + "/" + dataFileNum,
readForDataFile);
}
MappedByteBuffer readMappedByteFile = readForDataFile
.getMappedByteBuffer();
int writePos = (int) readForDataFile.getWritePosition().get();
logger.error("int writePos = (int) readForDataFile.getWritePosition().get();="
+ writePos);
// 定位到读位置然后获取byte数据
int currentPos = offset + size + 4;
// 当前data文件中
if (currentPos < writePos) {
do {
readMappedByteFile.position(currentPos);
long nextSize = readMappedByteFile.getInt();
long[] t = new long[3];
t[0] = currentPos;
t[1] = nextSize;
t[2] = dataFileNum;
logger.error("t[0] = currentPos;t[1] = nextSize;t[2]=dataFileNum;"
+ t.toString());
rs.add(t);
currentPos += nextSize + 4;
} while (currentPos < writePos);
// 判断是否还有下一个data文件,并进行恢复
ArrayList<Integer> fileNameList = Comm.getFileNum(this.filePath);
for (int i=0; i < fileNameList.size(); i++) {
if(fileNameList.get(i)>dataFileNum){
currentPos=16;
dataFileNum=fileNameList.get(i);
do {
readMappedByteFile.position(currentPos);
long nextSize = readMappedByteFile.getInt();
long[] t = new long[3];
t[0] = currentPos;
t[1] = nextSize;
t[2] = dataFileNum;
logger.error("t[0] = currentPos;t[1] = nextSize;t[2]=dataFileNum;"
+ t.toString());
rs.add(t);
currentPos += nextSize + 4;
} while (currentPos < writePos);
}
}
}
return rs;
}
/**
* 获取每个文件的名称地址
*
*/
private ArrayList<Integer> dataNumArray;
/**
* 创建或者获取当前使用的index文件 暂时以文件的数目来确定存储文件
*/
private void initFileInfo() {
dataNumArray = Comm.getFileNum(this.filePath);
if (this.dataNumArray == null || this.dataNumArray.size() == 0) {
logger.warn("create index file");
this.dataMappedFile = new MappedFileInfo(this.filePath + "/0");
this.dataNum = 0;
this.fileCount = 1;
this.dataNumArray.add(0);
} else {
// 判断文件的最大编号
int max = dataNumArray.get(dataNumArray.size() - 1);
logger.warn("max index " + max);
this.dataNum = max;
this.dataMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.dataNum);
this.fileCount = dataNumArray.size();
}
logger.error("initFileInfo 创建了一个datafile + this.datanum==="
+ this.dataNum);
readDataFileMap.put(this.filePath + "/" + this.dataNum,
this.dataMappedFile);
}
/**
* 保存data数据到data文件
*
* @param data
* @return
*/
public long addData(byte[] data) {
// 保存当写入失败是上次写的位置
long lastWritePosition = this.dataMappedFile.getWritePosition().get();
boolean addDataFlag = this.dataMappedFile.saveData(data);
if (!addDataFlag) {
logger.error("增加数据时当前data文件空间不够 ,将新建data文件");
// 恢复data的写位置
this.dataMappedFile.setWritePosition(new AtomicLong(
lastWritePosition));
this.dataMappedFile.setWritePositionToFile(lastWritePosition);
this.dataMappedFile.flush();
// 新建data文件
this.dataMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.fileCount);
this.dataNum = this.fileCount;
dataNumArray.add((int) this.dataNum);
Collections.sort(dataNumArray);
this.fileCount++;
// 重新写入文件
return this.addData(data);
}
return lastWritePosition;
// this.dataMappedFile.flush();
}
/**
* 保存data数据到data文件
*
* @param data
* @return
*/
public long addData_new(byte[] data) {
// 保存当写入失败是上次写的位置
long lastWritePosition = this.dataMappedFile.getWritePosition().get();
// 新存储data
boolean addDataFlag = this.dataMappedFile.saveData(data);
if (!addDataFlag) {
logger.error("增加数据时当前data文件空间不够 将新建data文件");
// 恢复data的写位置
this.dataMappedFile.setWritePosition(new AtomicLong(
lastWritePosition));
this.dataMappedFile.setWritePositionToFile(lastWritePosition);
this.dataMappedFile.flush();
// 新建data文件
this.dataMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.fileCount);
this.dataNum = this.fileCount;
dataNumArray.add((int) this.dataNum);
Collections.sort(dataNumArray);
this.fileCount++;
// 重新写入文件
return this.addData(data);
}
return lastWritePosition;
// this.dataMappedFile.flush();
}
/**
* 保存dataList数据到data文件
*
* @param data
* @return
*/
public long[] addDataByOnce(List<byte[]> dataList) {
// 保存当写入失败是上次写的位置
long lastWritePosition = this.dataMappedFile.getWritePosition().get();
long[] result = this.dataMappedFile.saveDataByOnce(dataList);
if (result == null) {
logger.error("增加数据时当前data文件空间不够 将新建data文件");
// 恢复data的写位置
this.dataMappedFile.setWritePosition(new AtomicLong(
lastWritePosition));
this.dataMappedFile.setWritePositionToFile(lastWritePosition);
this.dataMappedFile.flush();
// 新建data文件
this.dataMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.fileCount);
this.dataNum = this.fileCount;
// 加入数据并排序
dataNumArray.add((int) this.dataNum);
Collections.sort(dataNumArray);
this.fileCount++;
// 重新写入文件
logger.error("增加数据时当前data文件空间不够 将新建data文件" + dataNum);
return this.addDataByOnce(dataList);
}
return result;
// this.dataMappedFile.flush();
}
/**
* 将文件buffer刷新落盘保持到磁盘
*/
public void flush() {
this.dataMappedFile.flush();
}
/**
* 从指定文件中获取byte[]数据
*
* @param offset
* 指定文件读取位置 size 读取大小 dataFileName 数据文件
* @return byte[]数据
*/
public byte[] getData(long[] dataPos) {
return getData((int) dataPos[0], (int) dataPos[1], (int) dataPos[2]);
}
/**
* 获取一组数据
*
*/
public List<byte[]> getDataByOnce(List<long[]> dataIndexList) {
List<byte[]> result = new ArrayList<byte[]>();
for (int i = 0; i < dataIndexList.size(); i++) {
long[] dataPos = dataIndexList.get(i);
result.add(getData((int) dataPos[0], (int) dataPos[1],
(int) dataPos[2]));
}
return result;
}
/**
* 把数据从data文件的读出
*
* @param Offset
* 在data文件中的位置
* @param size
* 写入data文件中数据的大小
* @param dataFileNum
* 写入data文件的名称
* @return
*
*/
public byte[] getData(int offset, int size, int dataFileNum) {
// 保存已经开打的再读data文件
MappedFileInfo readForDataFile = readDataFileMap.get(this.filePath
+ "/" + dataFileNum);
if (readForDataFile == null) {
readForDataFile = new MappedFileInfo(this.filePath + "/"
+ dataFileNum);
readDataFileMap.put(this.filePath + "/" + dataFileNum,
readForDataFile);
}
MappedByteBuffer readMappedByteFile = readForDataFile
.getMappedByteBuffer();
// 定位到读位置然后获取byte数据
readMappedByteFile.position(offset + 4);
byte[] tempData = new byte[size];
readMappedByteFile.get(tempData);
return tempData;
}
/**
* 把数据从data文件的读出 带msg大小的标识
*
* @param Offset
* 在data文件中的位置
* @param size
* 写入data文件中数据的大小
* @param dataFileNum
* 写入data文件的名称
* @return
*
*/
public byte[] getData_new(int offset, int size, int dataFileNum) {
// 保存已经开打的再读data文件
System.out.println("int offset, int size, int dataFileNum=" + offset
+ " " + size + " " + dataFileNum);
MappedFileInfo readForDataFile = readDataFileMap.get(this.filePath
+ "/" + dataFileNum);
if (readForDataFile == null) {
readForDataFile = new MappedFileInfo(this.filePath + "/"
+ dataFileNum);
readDataFileMap.put(this.filePath + "/" + dataFileNum,
readForDataFile);
}
MappedByteBuffer readMappedByteFile = readForDataFile
.getMappedByteBuffer();
// 定位到读位置然后获取byte数据
readMappedByteFile.position(offset + 4);
byte[] tempData = new byte[size];
readMappedByteFile.get(tempData);
return tempData;
}
/**
* 获取从读位置到写位置的所有的数据
*
* @return
*/
public byte[] getData() {
return this.dataMappedFile.getData();
}
public long getFileSize() {
return fileSize;
}
public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}
public long getFileCount() {
return fileCount;
}
public void setFileCount(long fileCount) {
this.fileCount = fileCount;
}
public MappedFileInfo getDataMappedFile() {
return dataMappedFile;
}
public void setDataMappedFile(MappedFileInfo dataMappedFile) {
this.dataMappedFile = dataMappedFile;
}
public FileChannel getFileChannel() {
return fileChannel;
}
public void setFileChannel(FileChannel fileChannel) {
this.fileChannel = fileChannel;
}
public MappedByteBuffer getMappedByteBuffer() {
return mappedByteBuffer;
}
public void setMappedByteBuffer(MappedByteBuffer mappedByteBuffer) {
this.mappedByteBuffer = mappedByteBuffer;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public long getDataNum() {
return dataNum;
}
public void setDataNum(long dataNum) {
this.dataNum = dataNum;
}
public void destory() {
// TODO Auto-generated method stub
// this.mappedByteBuffer
}
/**
* 重新设置写位置
*/
public void resetFilePosition() {
this.dataMappedFile.setWritePositionToFile(16);
this.dataMappedFile.setWritePosition(new AtomicLong(16));
}
}

View File

@@ -0,0 +1,330 @@
package com.alibaba.middleware.race.mom.store;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.middleware.race.mom.broker.function.Offset;
public class FileStoreManager {
private static Logger logger = LoggerFactory
.getLogger(FileStoreManager.class);
// 索引文件
private IndexMappedFile indexMappedFile;
// 数据文件
private DataMappedFile dataMappedFile;
private String filePath;
// 最后一次刷数据的时间
private long lastFlushTime = System.currentTimeMillis();
private long lastIndexFlushTime = System.currentTimeMillis();
// 读写锁保证线程安全
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
// 统计已经写入但为落盘到磁盘的消息数目
private static AtomicLong countMsg = new AtomicLong(0);
// 落盘时同步等待index和data文件的缓存落盘到磁盘
private CountDownLatch countDownLatch;
// index和data文件多线程并行落盘
private ExecutorService flushPool = Executors.newFixedThreadPool(1);
private ExecutorService flushIndexPool = Executors.newFixedThreadPool(1);
public FileStoreManager(String filePath) {
this.filePath = filePath;
this.indexMappedFile = new IndexMappedFile(filePath + "/index");
this.dataMappedFile = new DataMappedFile(filePath + "/data");
// logger.debug("初始化filestoremanager成功" + filePath);
}
public FileStoreManager(String filePath, String test) {
this.filePath = filePath;
this.indexMappedFile = new IndexMappedFile(filePath + "/index");
this.dataMappedFile = new DataMappedFile(filePath + "/data");
// logger.debug("初始化filestoremanager成功" + filePath);
this.recover();
}
void recover() {
long[] lastWrittePosition = this.indexMappedFile.getLastWriteData();
// logger.error("long[] lastWrittePosition=="+lastWrittePosition.toString());
List<long[]> rs = this.dataMappedFile.checkLastMsg(lastWrittePosition);
if (rs == null || rs.size() == 0) {
return;
} else {
for (long[] temp : rs) {
logger.error("新恢复增加indexdata " + temp[0] + " / " + temp[1]
+ " / " + temp[2]);
this.indexMappedFile.addData(temp[0], (int) temp[1],
(int) temp[2]);
}
}
}
/**
* 保存一个字节到index和data文件中
*
* @param msg
*/
private void saveMessage(byte[] msg) {
lock.writeLock().lock();
try {
// 在data文件中增加记录
int dataWritePosition = (int) this.dataMappedFile.addData(msg);
int size = msg.length;
int fileNum = (int) this.dataMappedFile.getDataNum();
// logger.debug("dataWritePosition,size,fileNum= " +
// dataWritePosition
// + "," + size + "," + fileNum);
// 写入index文件中
boolean flag = this.indexMappedFile.addData(dataWritePosition,
size, fileNum);
if (!flag) {
logger.warn("没有存成功未知原因在index文件中");
}
logger.debug("成功将字节写入文件");
} finally {
lock.writeLock().unlock();
}
}
/**
* 保存数据 提供给其他调用的接口必须是以List包装的字节数据传入的参数最好用ArrayList
*/
static long savemessage = 0;
public boolean saveMessage(List<byte[]> msgList) {
long t1 = System.currentTimeMillis();
for (int i = 0; i < msgList.size(); i++) {
byte[] temp = msgList.get(i);
countMsg.addAndGet(1);
saveMessage(temp);
}
flush();
long t2 = System.currentTimeMillis();
// savemessage += (t2 - t1);
logger.error("flush time t2-t1= " + (t2 - t1));
return true;
}
/**
* 保存数据 提供给其他调用的接口必须是以List包装的字节数据传入的参数最好用ArrayList
*/
static long savemessagebyonce = 0;
public boolean saveMessageByOnce(List<byte[]> msgList) {
long t1 = System.currentTimeMillis();
// 获取data文件存储结果
logger.debug("开始组进入写data文件 msgList.size()==" + msgList.size());
long[] dataResult = this.dataMappedFile.addDataByOnce(msgList);
long dataFileNum = this.dataMappedFile.getDataNum();
logger.debug("开始进入写index文件 dataResult.length= " + dataResult.length);
boolean indexFlag = this.indexMappedFile.addDataByOnce(dataResult,
(int) dataFileNum);
flush();
long t2 = System.currentTimeMillis();
logger.error("flush time t2-t1= " + (t2 - t1));
// savemessagebyonce += (t2 - t1);
return indexFlag;
}
/**
* 获取第0条到写的位置条数据, 恢复订阅数据用的函数
*
* @return
*/
public List<Offset> getSubscribe() {
ByteBuffer indexByte = ByteBuffer.wrap(this.indexMappedFile.getData());
ByteBuffer dataByte = ByteBuffer.wrap(this.dataMappedFile.getData());
int count = indexByte.capacity() / 16;
List<Offset> subscribeInfoList = new ArrayList<Offset>(count);
for (int i = 0; i < count; i++) {
indexByte.position(i * 16);
long dataStart = indexByte.getLong();
int size = indexByte.getInt();
dataByte.position((int) dataStart - 16 + 4);
byte[] temp = new byte[size];
dataByte.get(temp);
subscribeInfoList
.add((Offset) JSON.parseObject(temp, Offset.class));
}
return subscribeInfoList;
}
/**
* 获取第startCount条到endCount条数据 采用一组数据一组数据的读
*
* @param startCount
* @param endCount
* @return
*/
public ArrayList<byte[]> getMessageByOnce(int offset, int maxOffset) {
logger.warn("开始组获取数据了");
List<long[]> dataIndexList = this.indexMappedFile.getIndexDataByOnce(
offset, maxOffset);
return (ArrayList<byte[]>) this.dataMappedFile
.getDataByOnce(dataIndexList);
}
/**
* 获取第startCount条到endCount条数据
*
* @param startCount
* @param endCount
* @return
*/
public List<byte[]> getMessage(int startCount, int endCount) {
lock.readLock().lock();
List<byte[]> msgList = null;
try {
msgList = new ArrayList<byte[]>(endCount - startCount + 1);
// logger.debug(" return msgList.size() endCount - startCount + 1 = "
// + (endCount - startCount + 1));
for (int i = startCount; i <= endCount; i++) {
// logger.debug("i= " + i);
long[] returnIndexData = this.indexMappedFile.getData(i);
// logger.debug(" returnIndexData= " + returnIndexData[0] +
// " , "
// + returnIndexData[1] + " , " + returnIndexData[2] + " , ");
byte[] temp = this.dataMappedFile.getData(returnIndexData);
// logger.debug("temp.size()= " + temp.length);
msgList.add(temp);
}
} catch (Exception e) {
} finally {
lock.readLock().unlock();
}
return msgList;
}
/**
* 多线程并行落盘
*/
public void flush() {
lock.writeLock().lock();
countDownLatch = new CountDownLatch(2);
flushIndexPool.execute(new Thread() {
@Override
public void run() {
long t1 = System.currentTimeMillis();
// 索引文件异步
try {
FileStoreManager.this.indexMappedFile.flush();
countDownLatch.countDown();
} finally {
// countDownLatch.countDown();
}
long t2 = System.currentTimeMillis();
// System.out.println(" force index t2-t1==" + (t2 - t1));
}
});
flushPool.execute(new Thread() {
@Override
public void run() {
long t1 = System.currentTimeMillis();
try {
FileStoreManager.this.dataMappedFile.flush();
} finally {
countDownLatch.countDown();
}
long t2 = System.currentTimeMillis();
// System.out.println(" force data t2-t1==" + (t2 - t1));
}
});
try {
countDownLatch.await();
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
lock.writeLock().unlock();
}
// 测试用的
// flushPool.shutdown();
}
/**
* 多线程并行落盘
*/
/*
* public void flush() { lock.writeLock().lock(); countDownLatch = new
* CountDownLatch(2);
*
* flushIndexPool.execute(new Thread() {
*
* @Override public void run() { long t1 = System.currentTimeMillis();
*
* // 索引文件异步 try { FileStoreManager.this.indexMappedFile.flush();
* countDownLatch.countDown(); } finally { // countDownLatch.countDown(); }
* long t2 = System.currentTimeMillis(); //
* System.out.println(" force index t2-t1==" + (t2 - t1)); } });
*
* flushPool.execute(new Thread() {
*
* @Override public void run() { long t1 = System.currentTimeMillis(); try {
* FileStoreManager.this.dataMappedFile.flush(); } finally {
* countDownLatch.countDown(); } long t2 = System.currentTimeMillis(); //
* System.out.println(" force data t2-t1==" + (t2 - t1)); } });
*
* try { countDownLatch.await(); } catch (Exception e) {
* logger.error(e.getMessage()); } finally { lock.writeLock().unlock(); }
*
* // 测试用的 // flushPool.shutdown(); }
*/
/**
* 释放资源
*/
public void destory() {
this.indexMappedFile.destory();
this.dataMappedFile.destory();
}
public void resetFilePosition() {
this.indexMappedFile.resetFilePosition();
this.dataMappedFile.resetFilePosition();
}
/**
* 获取第0条到写的位置条数据, 恢复OffsetNum数据用的函数
*
* @return
*/
public List<OffsetNum> getOffsetNum() {
ByteBuffer indexByte = ByteBuffer.wrap(this.indexMappedFile.getData());
ByteBuffer dataByte = ByteBuffer.wrap(this.dataMappedFile.getData());
int count = indexByte.capacity() / 16;
List<OffsetNum> offsetNumList = new ArrayList<OffsetNum>(count);
for (int i = 0; i < count; i++) {
indexByte.position(i * 16);
long dataStart = indexByte.getLong();
int size = indexByte.getInt();
dataByte.position((int) dataStart - 16 + 4);
byte[] temp = new byte[size];
dataByte.get(temp);
offsetNumList.add((OffsetNum) JSON.parseObject(temp,
OffsetNum.class));
}
return offsetNumList;
}
}

View File

@@ -0,0 +1,296 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IndexMappedFile {
// 文件编号
private long indexNum;
// 文件大小
private long fileSize;
// 文件数目
private long fileCount = 0;
// index文件
private MappedFileInfo indexMappedFile;
// 文件的fileChannel
private FileChannel fileChannel;
// 文件的MappedByteBuffer
private MappedByteBuffer mappedByteBuffer;
// 文件夹的路径
private String filePath;
// 保存已经打开的读文件列表
ConcurrentHashMap<String, MappedFileInfo> readIndexFileMap = new ConcurrentHashMap<String, MappedFileInfo>();
private static Logger logger = LoggerFactory
.getLogger(IndexMappedFile.class);
public long[] getLastWriteData() {
long[] result=null;
long pos = this.indexMappedFile.getWritePosition().get();
if (pos == 16) {
//初始状态
return result;
}
this.indexMappedFile.getMappedByteBuffer().position((int) (this.indexMappedFile
.getWritePosition().get() - 16));
long offset = this.indexMappedFile.getMappedByteBuffer().getLong();
logger.error("从index 读出data 的位置offset====" + offset);
int size = this.indexMappedFile.getMappedByteBuffer().getInt();
int dataFileNum = this.indexMappedFile.getMappedByteBuffer().getInt();
result = new long[] { offset, size, dataFileNum };
return result;
}
/**
* 构造函数
*
* @param filePath
*/
public IndexMappedFile(String filePath) {
this.filePath = filePath;
this.initFileInfo();
/*
* this.mappedByteBuffer = this.indexMappedFile.getMappedByteBuffer();
* this.fileChannel = this.indexMappedFile.getFileChannel();
*/
}
/**
* 获取每个文件的名称地址
*
*/
private ArrayList<Integer> indexNumArray;
/**
* 创建或者获取当前使用的index文件 暂时以文件的数目来确定存储文件
*/
private void initFileInfo() {
indexNumArray = Comm.getFileNum(this.filePath);
if (this.indexNumArray == null || this.indexNumArray.size() == 0) {
logger.warn("create index file");
this.indexMappedFile = new MappedFileInfo(this.filePath + "/0");
this.indexNum = 0;
this.fileCount = 1;
this.indexNumArray.add(0);
} else {
// 判断文件的最大编号
int max = indexNumArray.get(indexNumArray.size() - 1);
logger.error("max index " + max);
this.indexNum = max;
this.indexMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.indexNum);
this.fileCount = indexNumArray.size();
}
logger.error("inti file createFile 创建了一个indexfile + this.indexnum==="
+ this.indexNum);
readIndexFileMap.put(this.filePath + "/" + this.indexNum,
this.indexMappedFile);
}
/**
* 把数据在data文件的写入信息保存到index文件中
*
* @param dataOffset
* 在data文件中的位置
* @param size
* 写入data文件中数据的大小
* @param dataFileNum
* 写入data文件的名称
* @return
*/
public boolean addData(long dataOffset, int size, int dataFileNum) {
// 保存当写入失败是上次写的位置
long lastWritePosition = this.indexMappedFile.getWritePosition().get();
// 依次写入data数据信息
boolean[] addDataFlag = new boolean[3];
addDataFlag[0] = this.indexMappedFile.saveData(dataOffset);
addDataFlag[1] = this.indexMappedFile.saveData(size);
addDataFlag[2] = this.indexMappedFile.saveData(dataFileNum);
if (!(addDataFlag[0] && addDataFlag[1] && addDataFlag[2])) {
logger.error("增加数据时当前index文件空间不够 将新建index文件");
// 恢复index的写位置
this.indexMappedFile.setWritePosition(new AtomicLong(
lastWritePosition));
this.indexMappedFile.setWritePositionToFile(lastWritePosition);
this.indexMappedFile.flush();
// 新建index文件
// 新建index文件,文件名为开始记录
logger.error("index 增加数据时当前index文件空间不够 将新建index文件 old this.indexNum="
+ this.indexNum
+ " /lastWritePosition=="
+ lastWritePosition);
this.indexNum += ((lastWritePosition / 16) - 1);
logger.error("index 增加数据时当前index文件空间不够 将新建index文件 new this.indexNum="
+ this.indexNum);
// 加入数组中,默认是加到数据末尾
indexNumArray.add((int) this.indexNum);
this.indexMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.indexNum);
logger.error("index 增加数据时当前index文件空间不够 将新建index文件 his.indexNum"
+ this.indexNum);
this.fileCount++;
// 重新写入文件
return this.addData(dataOffset, size, dataFileNum);
}
logger.debug("增加index数据时 成功");
return true;
}
/**
* 把数据在data文件的写入信息保存到index文件中
*
* @param dataOffset
* 在data文件中的位置
* @param size
* 写入data文件中数据的大小
* @param dataFileNum
* 写入data文件的名称
* @return
*/
public boolean addDataByOnce(long[] dataArray, int dataFileNum) {
// 保存当写入失败是上次写的位置
long lastWritePosition = this.indexMappedFile.getWritePosition().get();
// 依次写入data数据信息
boolean addDataFlag = this.indexMappedFile.saveDataByOnce(dataArray,
dataFileNum);
if (!addDataFlag) {
logger.error("增加数据时当前index文件空间不够 将新建index文件");
// 恢复index的写位置
this.indexMappedFile.setWritePosition(new AtomicLong(
lastWritePosition));
this.indexMappedFile.setWritePositionToFile(lastWritePosition);
this.indexMappedFile.flush();
// 新建index文件,文件名为开始记录
this.indexNum += ((lastWritePosition / 16) - 1);
// 加入数组中,默认是加到数据末尾
indexNumArray.add((int) this.indexNum);
logger.error("create index file name indexnum== " + this.indexNum);
logger.error("index 增加数据时当前index文件空间不够 将新建index文件 indexNumArray.SIZE()"
+ indexNumArray.size());
this.indexMappedFile = new MappedFileInfo(this.filePath + "/"
+ this.indexNum);
this.fileCount++;
// 重新写入文件
return this.addDataByOnce(dataArray, dataFileNum);
}
logger.debug("增加index数据时 成功");
return true;
// this.indexMappedFile.flush();
}
/**
* 将文件buffer落盘保持到磁盘
*/
public long flush() {
return this.indexMappedFile.flush();
}
/**
* 获取信息防护给data文件读取数据 获取指定位置的一个单位(8+4+4)
*
*/
public long[] getData(int countStart) {
// 获取需要打开index文件名
if (indexNumArray == null || indexNumArray.size() == 0) {
logger.error(" 没有 index file 存在countStart= " + countStart);
return null;
} else {
// 判断文件的最大编号
int fileCount = indexNumArray.size();
int readIndexFileNum = 0;
for (int i = (fileCount - 1); i >= 0; i--) {
// logger.debug("get data create index filedir count tempNum= "
// + readIndexFileNum);
int t = indexNumArray.get(i);
if (t > countStart) {
continue;
} else {
readIndexFileNum = t;
break;
}
}
// 转化到当前文件的文件内地址
logger.debug("转化到当前文件的文件内地址 readIndexFileNum___" + readIndexFileNum);
MappedFileInfo readForIndexFile = readIndexFileMap
.get(this.filePath + "/" + readIndexFileNum);
if (readForIndexFile == null) {
readForIndexFile = new MappedFileInfo(this.filePath + "/"
+ readIndexFileNum);
readIndexFileMap.put(this.filePath + "/" + readIndexFileNum,
readForIndexFile);
logger.error("创建读index文件 " + this.filePath + "/"
+ readIndexFileNum);
}
// logger.debug("读index文件 " + this.filePath + "/" + fileNum);
// 将countStart转化为指定index文件的相对地址注意要偏移16位
int tempPosition = (countStart - readIndexFileNum) * 16 + 16;
MappedByteBuffer readMappedByteFile = readForIndexFile
.getMappedByteBuffer();
readMappedByteFile.position((int) tempPosition);
logger.error("在读出index 数据的 位置 tempPosition====" + tempPosition);
// 获取与data文件记录相关信息
long offset = readMappedByteFile.getLong();
logger.error("从index 读出data 的位置offset====" + offset);
int size = readMappedByteFile.getInt();
int dataFileNum = readMappedByteFile.getInt();
long[] result = new long[] { offset, size, dataFileNum };
return result;
}
}
/**
* 获取信息防护给data文件读取数据 获取指定位置的一个单位(8+4+4)
*
*/
public List<long[]> getIndexDataByOnce(int countStart, int countEnd) {
List<long[]> result = new ArrayList<long[]>();
for (int i = countStart; i <= countEnd; i++) {
logger.error("int i = countStart; i <= countEnd" + i
+ " int countStart, int countEnd== " + countStart + " , "
+ countEnd);
result.add(this.getData(i));
}
return result;
}
/**
* 获取从读位置到写位置的所有的数据
*
* @return
*/
public byte[] getData() {
return this.indexMappedFile.getData();
}
public void destory() {
// this.indexMappedFile
}
/**
* 重新设置写位置
*/
public void resetFilePosition() {
this.indexMappedFile.setWritePositionToFile(16);
this.indexMappedFile.setWritePosition(new AtomicLong(16));
}
}

View File

@@ -0,0 +1,416 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MappedFileInfo {
// 文件大小
private static long MAX_FILE_SIZE = 1024 * 1024 * 1024;
// 文件读写位置
private AtomicLong writePosition = new AtomicLong(0);
private AtomicLong readPosition = new AtomicLong(0);
// 上一次刷的文件位置
private AtomicLong lastFlushFilePosition = new AtomicLong(0);
// 最后一次刷数据的时间
private long lastFlushTime = System.currentTimeMillis();
// 文件路径和名称全称
private String filePathAndName;
// 文件的读取方式
private RandomAccessFile raf;
private MappedByteBuffer mappedByteBuffer;
// 映射的FileChannel对象
private FileChannel fileChannel;
private static Logger logger = LoggerFactory
.getLogger(MappedFileInfo.class);
/**
* 构建一个mappedFile文件
*
* @param filePathAndName
* 传入文件路径和名称
*/
public MappedFileInfo(String filePathAndName) {
this.filePathAndName = filePathAndName;
createRandomAccessFile();
getFileMappedByteBuffer(0, MAX_FILE_SIZE);
setInitPosition();
}
/**
* 构建一个mappedFile文件
*
* @param filePathAndName
* 文件路径和名称
* @param fileSize
* 文件大小
*/
public MappedFileInfo(String filePathAndName, long fileSize) {
this.filePathAndName = filePathAndName;
this.createRandomAccessFile();
this.getFileMappedByteBuffer(0, fileSize);
this.setInitPosition();
}
/**
* 初始化文件的读写位置变量 读位置8+写位置8 根据文件的前16个字节获取当前读和写的位置
*
*/
private void setInitPosition() {
// 文件前16字节存放读地址和写地址
this.mappedByteBuffer.position(0);
long position;
// 如果position=0则为起始地址16
if ((position = this.mappedByteBuffer.getLong()) == 0) {
this.readPosition.set(16);
} else {
this.readPosition.set(position);
}
// 更新读位置
this.mappedByteBuffer.position(0);
this.mappedByteBuffer.putLong(this.readPosition.get());
// logger.debug("this.readPosition= "+this.readPosition);
// 如果position=0则为起始地址16
if ((position = this.mappedByteBuffer.getLong()) == 0) {
this.writePosition.set(16);
this.lastFlushFilePosition.set(16);
} else {
this.writePosition.set(position);
this.lastFlushFilePosition.set(16);
}
// 更新写位置
this.mappedByteBuffer.position(8);
this.mappedByteBuffer.putLong(this.writePosition.get());
// logger.debug("this.writePosition= "+this.writePosition.get());
}
/**
* 建立和确保文件存在
*/
private synchronized void createRandomAccessFile() {
File f = new File(filePathAndName);
try {
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
}
this.raf = new RandomAccessFile(f, "rw");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 打开文件映射
*
* @param startPos
* @param fileSize
*/
private void getFileMappedByteBuffer(long startPos, long fileSize) {
try {
this.fileChannel = this.raf.getChannel();
this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE,
startPos, fileSize);
} catch (Exception e) {
logger.error("内存映射沒有建立");
logger.error(e.getMessage());
}
}
/**
* 保存一组index数据 index文件调用
*
* @param data
* @return
*/
public boolean saveDataByOnce(long[] dataArray, int fileNum) {
long lastposition = this.writePosition.get();
long currentPosition = lastposition;
if ((currentPosition + (dataArray.length / 3) * 16) > this.MAX_FILE_SIZE) {
// 恢复到存数据的开始
logger.warn("文件空间不够了,需要新建文件");
return false;
}
for (int i = 0; i < dataArray.length; i++) {
// 一定要定位写的位置
mappedByteBuffer.position((int) currentPosition);
mappedByteBuffer.putLong(dataArray[i]);
i++;
mappedByteBuffer.putInt((int) dataArray[i]);
i++;
mappedByteBuffer.putInt(fileNum);
currentPosition += 16;
}
// 完成后,设置写的写位置
this.writePosition.set(currentPosition);
this.lastFlushFilePosition.set(currentPosition);
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(currentPosition);
return true;
}
/**
* 保存一组data数据
*
* @param data
* @return
*/
public long[] saveDataByOnce(List<byte[]> dataList) {
long lastposition = this.writePosition.get();
long currentPosition = lastposition;
int count = dataList.size();
// 保存返回结果
long[] result = new long[count * 3];
for (int i = 0; i < count; i++) {
byte[] data = dataList.get(i);
if ((currentPosition + data.length + 4) > this.MAX_FILE_SIZE) {
// 恢复到存数据的开始
logger.warn("保存消息的数据文件空间不够了!");
currentPosition = lastposition;
result = null;
break;
} else {
// 表示有空余空间
if (i == 0) {
// 加快速度
mappedByteBuffer.position((int) currentPosition);
}
result[i * 3] = currentPosition;
result[3 * i + 1] = data.length;
mappedByteBuffer.putInt(data.length);
mappedByteBuffer.put(data);
currentPosition += data.length + 4;
}
}
// 设置写的写位置
this.writePosition.set(currentPosition);
this.lastFlushFilePosition.set(currentPosition);
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(currentPosition);
return result;
}
/**
* 保存单条数据
*
* @param data
* @return
*/
public boolean saveData(byte[] data) {
long position = this.writePosition.get();
logger.debug("save data[] this.writePosition.get() " + position);
// 表示有空余空间
if ((position + data.length + 4) <= this.MAX_FILE_SIZE) {
mappedByteBuffer.position((int) position);
mappedByteBuffer.putInt(data.length);
mappedByteBuffer.put(data);
this.writePosition.addAndGet(data.length + 4);
this.lastFlushFilePosition.addAndGet(data.length + 4);
// 更新文件前16字节writePostion
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(this.writePosition.get());
return true;
}
return false;
}
/**
* 保存单条数据 data文件 带长度位置的msg存储
*
* @param data
* @return
*/
public boolean saveData_new(byte[] data) {
int length = data.length;
long position = this.writePosition.get();
logger.error("save data[] this.writePosition.get() " + position);
logger.error("save data[] length() " + length);
// 表示有空余空间4byte镖师长度
if ((position + length + 4) <= this.MAX_FILE_SIZE) {
mappedByteBuffer.position((int) position);
mappedByteBuffer.putInt(length);
mappedByteBuffer.put(data);
this.writePosition.addAndGet(length + 4);
this.lastFlushFilePosition.addAndGet(length + 4);
// 更新文件前16字节writePostion
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(position + length + 4);
mappedByteBuffer.position(8);
// logger.error(" 写入 mappedByteBuffer.position(8)=="+mappedByteBuffer.getLong());
return true;
}
return false;
}
/**
* 设置文件的首写地址
*
* @param pos
*/
public void setWritePositionToFile(long pos) {
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(pos);
}
public boolean saveData(long data) {
long position = this.writePosition.get();
logger.debug("save long this.writePosition.get() " + position);
// 表示有空余空间
if ((position + 8) <= this.MAX_FILE_SIZE) {
mappedByteBuffer.position((int) position);
mappedByteBuffer.putLong(data);
this.writePosition.addAndGet(8);
this.lastFlushFilePosition.addAndGet(8);
// 更新文件前16字节writePostion
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(this.writePosition.get());
return true;
}
return false;
}
public boolean saveData(int data) {
long position = this.writePosition.get();
logger.debug("save int this.writePosition.get() " + position);
// 表示有空余空间
if ((position + 4) <= this.MAX_FILE_SIZE) {
mappedByteBuffer.position((int) position);
mappedByteBuffer.putInt(data);
this.writePosition.addAndGet(4);
// 更新文件前16字节writePostion
mappedByteBuffer.position(8);
mappedByteBuffer.putLong(this.writePosition.get());
return true;
}
return false;
}
/**
* 进行刷新,将数据写入磁盘
*
* @return
*/
public long flush() {
this.mappedByteBuffer.force();
lastFlushFilePosition.set(this.writePosition.get());
this.lastFlushFilePosition = this.writePosition;
return this.lastFlushFilePosition.get();
}
/**
* 获取指定的位置的文件字节数据 暂时不用
*
* @param start
* @param end
* @return
*/
public byte[] getData(long start, long end) {
if (start < 0 || start > this.writePosition.get()) {
return null;
}
if (end > this.writePosition.get()) {
end = this.writePosition.get();
}
int size = (int) (end - start);
byte[] temp = new byte[size];
this.mappedByteBuffer.position((int) start);
this.mappedByteBuffer.get(temp);
return temp;
}
/**
* 获取从读位置到写位置的所有数据作为一个数组 恢复订阅关系使用
*
* @return
*/
public byte[] getData() {
int size = (int) (this.writePosition.get() - this.readPosition.get());
logger.debug(this.writePosition.get() + " , "
+ this.readPosition.get());
byte[] temp = new byte[size];
this.mappedByteBuffer.position((int) this.readPosition.get());
this.mappedByteBuffer.get(temp);
return temp;
}
public AtomicLong getWritePosition() {
return writePosition;
}
public void setWritePosition(AtomicLong writePosition) {
this.writePosition = writePosition;
}
public AtomicLong getReadPosition() {
return readPosition;
}
public void setReadPosition(AtomicLong readPosition) {
this.readPosition = readPosition;
}
public AtomicLong getLastFlushFilePosition() {
return lastFlushFilePosition;
}
public void setLastFlushFilePosition(AtomicLong lastFlushFilePosition) {
this.lastFlushFilePosition = lastFlushFilePosition;
}
public long getLastFlushTime() {
return lastFlushTime;
}
public void setLastFlushTime(long lastFlushTime) {
this.lastFlushTime = lastFlushTime;
}
public String getFilePathAndName() {
return filePathAndName;
}
public void setFilePathAndName(String filePathAndName) {
this.filePathAndName = filePathAndName;
}
public RandomAccessFile getRaf() {
return raf;
}
public void setRaf(RandomAccessFile raf) {
this.raf = raf;
}
public MappedByteBuffer getMappedByteBuffer() {
return mappedByteBuffer;
}
public void setMappedByteBuffer(MappedByteBuffer mappedByteBuffer) {
this.mappedByteBuffer = mappedByteBuffer;
}
public FileChannel getFileChannel() {
return fileChannel;
}
public void setFileChannel(FileChannel fileChannel) {
this.fileChannel = fileChannel;
}
public static long getMaxFileSize() {
return MAX_FILE_SIZE;
}
}

View File

@@ -0,0 +1,129 @@
package com.alibaba.middleware.race.mom.store;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Message implements Serializable{
/**
*
*/
private static final long serialVersionUID = 5295808332504208830L;
private String topic;
private byte[] body;
//全局唯一的消息id不同消息不能重复
private String msgId;
private int offset;
private long bornTime;
private Map<String, String> properties = new HashMap<String, String>();
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public String getTopic() {
return topic;
}
public void setBody(byte[] body) {
this.body = body;
}
public byte[] getBody() {
return body;
}
public String getProperty(String key) {
return properties.get(key);
}
/**
* 设置消息属性
* @param key
* @param value
*/
public void setProperty(String key, String value) {
properties.put(key, value);
}
/**
* 删除消息属性
* @param key
*/
public void removeProperty(String key) {
properties.remove(key);
}
public long getBornTime() {
return bornTime;
}
public void setBornTime(long bornTime) {
this.bornTime = bornTime;
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(body);
result = prime * result + (int) (bornTime ^ (bornTime >>> 32));
result = prime * result + ((msgId == null) ? 0 : msgId.hashCode());
result = prime * result + ((properties == null) ? 0 : properties.hashCode());
result = prime * result + ((topic == null) ? 0 : topic.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Message other = (Message) obj;
if (!Arrays.equals(body, other.body))
return false;
if (bornTime != other.bornTime)
return false;
if (msgId == null) {
if (other.msgId != null)
return false;
} else if (!msgId.equals(other.msgId))
return false;
if (properties == null) {
if (other.properties != null)
return false;
} else if (!properties.equals(other.properties))
return false;
if (topic == null) {
if (other.topic != null)
return false;
} else if (!topic.equals(other.topic))
return false;
return true;
}
@Override
public String toString() {
return "Message [topic=" + topic + ", body=" + Arrays.toString(body) + ", msgId=" + msgId + ", bornTime="
+ bornTime + ", properties=" + properties + "]";
}
}

View File

@@ -0,0 +1,161 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.LinkedList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.middleware.race.mom.Message;
/**
*测试用的代码,是这样提供功能吗?
*没有考虑内存映射,优化,锁,并发,只是功能,
*大家看一下,这些接口提供了你们想的信息吗?
* 不明白offset 我暂时理解为在index中的实际位置根据这个位置可以读一个long值代表datafile中的实际数据的地址。
*/
public class MsgFileUtil {
Logger logger = LoggerFactory.getLogger(MsgFileUtil.class);
static String fileRoot = System.getProperty("user.home");
static String fileSpt = System.getProperty("file.separator");
private RandomAccessFile getFile(String topic, String groupId, String queueId, String fileName) throws IOException {
String fileStr;
if (queueId == null || queueId.equals("") || queueId.isEmpty()) {
// fileStr = fileRoot + fileSpt + "store" + fileSpt + "normal" +
// fileSpt + topic + fileSpt + queueId + fileSpt +fileName;
fileStr = fileRoot + "/store/normal/" + topic + "/" + queueId + "/" + fileName;
} else {
// fileStr = fileRoot + fileSpt + "store" + fileSpt + "retry" +
// fileSpt + groupId + fileSpt + fileName;
fileStr = fileRoot + "/store/retry/" + groupId + "/" + fileName;
}
File f = new File(fileStr);
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
}
return new RandomAccessFile(f, "rw");
}
/*
* 给定 索引文件的地址offset返回对应data文件的msg
*
*/
public List<Message> getMsg(String topic, String queueId, String groupId, Long offset) throws IOException {
if (offset < 0) {
return null;
}
return getMsg(topic, queueId, groupId, offset, offset);
}
/*
* 根据请求参数传回List<Message>
*
*
*/
public List<Message> getMsg(String topic, String queueId, String groupId, Long offset, Long maxOffset)
throws IOException {
List<Message> resultMsg = new LinkedList<Message>();
RandomAccessFile indexFile, dataFile;
// 根据是否有queueId判定文件位置
if (queueId == null || queueId.equals("") || queueId.isEmpty()) {
indexFile = getFile(topic, null, queueId, "index.file");
dataFile = getFile(topic, null, queueId, "data.file");
} else {
indexFile = getFile(null, groupId, null, "index.file");
dataFile = getFile(null, groupId, null, "data.file");
}
// 找到index文件的offset读出真正的data文件的offset
while (offset <= maxOffset && offset < indexFile.length()) {
indexFile.seek(offset);
long dataOffset = indexFile.readLong();
int dataSize = indexFile.readInt();
// 根据dataoffset读出 msg
dataFile.seek(dataOffset);
byte[] msgBody = new byte[dataSize];
dataFile.read(msgBody);
// 读出内容将index文件的type类型设置为已经读“1”
indexFile.seek(offset + 12);
indexFile.writeInt(1);
Message msgTemp = JSON.parseObject(msgBody, Message.class);
resultMsg.add(msgTemp);
offset += 16;
}
return resultMsg;
}
/*
* 返回一个队列中所有消息
*/
public List<Message> getMsg(String topic, String queueId, String groupId) throws IOException {
long offset = 0;
long maxOffset = Long.MAX_VALUE;
return getMsg(topic, queueId, groupId, offset, maxOffset);
}
/*
* 给定 indexfile unit { offen(long),length(int),type(int)}
*/
public boolean setMsg(String topic, String queueId, String groupId, Message msg) throws Exception {
RandomAccessFile indexFile, dataFile;
if (queueId == null || queueId.equals("") || queueId.isEmpty()) {
indexFile = getFile(topic, null, queueId, "index.file");
dataFile = getFile(topic, null, queueId, "data.file");
} else {
indexFile = getFile(null, groupId, null, "index.file");
dataFile = getFile(null, groupId, null, "data.file");
}
byte[] msgByte = JSON.toJSONBytes(msg);
long dataPos = dataFile.length();
long indexPos = indexFile.length();
//System.out.println("indexpos,datapos=" + indexPos + "," + dataPos);
// 写入index
indexFile.seek(indexPos);
indexFile.writeLong(dataPos);
indexFile.writeInt(msgByte.length);
indexFile.writeInt(0);
// 写入data
dataFile.seek(dataPos);
dataFile.write(msgByte);
//System.out.println("indexpos,datapos=" + indexFile.length() + "," + dataFile.length());
/*
* //恢复数据 test dataPos=dataFile.length(); indexPos=indexFile.length();
* for(long i=0;i<indexFile.length();){ indexFile.seek(i); long
* offset=indexFile.readLong(); int size=indexFile.readInt(); int
* type=indexFile.readInt(); System.out.println("offset="+offset+
* " ,size="+size+" ,type="+type); dataFile.seek(offset); byte[]
* bufferTemp=new byte[size]; dataFile.read(bufferTemp);
* msg=JSON.parseObject(bufferTemp,Message.class);
* System.out.println(msg.toString()); i=indexFile.getFilePointer(); }
*/
return true;
}
public static void main(String[] args) throws Exception {
Message msg = new Message();
// msg.setMsgId("msgID");
msg.setBody("dddddfgf".getBytes());
msg.setBornTime(System.currentTimeMillis());
long startTime = System.currentTimeMillis();
new MsgFileUtil().setMsg("topic", "queueId", null, msg);
long endTime = System.currentTimeMillis();
System.out.println("统计 存一条数据 时间 endTime-startTime= " + (endTime - startTime));
startTime = System.currentTimeMillis();
List<Message> msgList = new MsgFileUtil().getMsg("topic", "queueId", null, 0L);
endTime = System.currentTimeMillis();
System.out.println("统计 取一条数据 时间 endTime-startTime= " + (endTime - startTime));
// test
System.out.println("main " + msgList.get(0).toString());
}
}

View File

@@ -0,0 +1,68 @@
package com.alibaba.middleware.race.mom.store;
import java.util.ArrayList;
import java.util.List;
/*
* By ChenQi
* 消息持久化接口
* */
public interface MsgStore {
/*
* index baseDir/Normal/Topic/GroupId/QueueId/index/ 0,1,2 data
* baseDir/Normal/Topic/GroupId/QueueId/data/ 0,1,2
*
*
* baseDir/Retry/Group/index/0,1,2 baseDir/Retry/Group/data/0,1,2
*/
// 一些参数定义初始化
public void init();
// 关闭
public void close();
// 存储正常消息, 成功true,失败false
public boolean writeByteNormal(String topicId, String queueId,
List<byte[]> msgList);
// 取消息每个消息的字节码存为list返回
public List<byte[]> readByteNormal(String topicID, String queueId,
int offset, int MaxOffset);
// 存储重试消息, 成功true,失败false
public boolean writeByteRetry(String groupId, List<byte[]> msgList);
// 取重试消息每个消息的字节码存为list返回
public ArrayList<byte[]> readByteRetry(String groupId, int offset,
int MaxOffset);
// 组写 为数据一组为单位在index 与data 文件分开写
boolean writeByteNormalByOnce(String topicId, String queueId,
List<byte[]> msgList);
// 组写 为数据一组为单位在index 与data 文件分开写
boolean writeByteRetryByOnce(String groupId, List<byte[]> msgList);
// 组读 为数据一组为单位在index 与data 文件分开读
List<byte[]> readByteNormalByOnce(String topicId, String queueId,
int offset, int MaxOffset);
// 组读 为数据一组为单位在index 与data 文件分开读
List<byte[]> readByteRetryByOnce(String queueId, int offset, int MaxOffset);
// 落盘-临时文件缓冲
/**
* 我传你的文件,你按顺序加入你的落盘逻辑,文件里的格式( 消息大小(int)+消息实体(body))
* 你需要一条一条读,然后读完一个文件刷一次就行。刷完就删除哈。 记住,可能你还没读完的时候
* 我又调用这个api传你另外一个文件所以你需要加入一个链表。 按顺序用完就删,不断的取。
*
* @param filename
*/
public void writeMappedFileTemp(String filename);
// test use
public void testprintlong();
public void loadAndRecover();
}

View File

@@ -0,0 +1,399 @@
//package com.alibaba.middleware.race.mom.store;
//
//import java.io.File;
//import java.io.FileDescriptor;
//import java.io.IOException;
//import java.io.RandomAccessFile;
//import java.nio.MappedByteBuffer;
//import java.nio.channels.FileChannel;
//import java.nio.channels.FileChannel.MapMode;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.concurrent.CountDownLatch;
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//import java.util.concurrent.atomic.AtomicLong;
//
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//
///*
// * baseDir/Normal/Topic/Group/Consumer/Queue/(index.file,data.file)
// * baseDir/Retry/Group/(index.file,data.file)
// * 题目没有consumerID就默认生成和groupID一样的
// * */
//
//public class MsgStoreImp_MappedBuffer implements MsgStore {
// private static Logger logger = LoggerFactory.getLogger(MsgStoreImp_MappedBuffer.class);
// public static final int OS_PAGE_SIZE = 1024 * 4;
// // 当前JVM中映射的虚拟内存总大小
// /*private static final AtomicLong TotalMapedVitualMemory = new AtomicLong(0);
// // 当前JVM中mmap句柄数量
// private static final AtomicInteger TotalMapedFiles = new AtomicInteger(0);*/
// // 文件大小
// private final static long MAX_FILE_SIZE = 1024 * 1024 * 1024;
// // 文件写入位置
// private AtomicLong indexWritePosition = new AtomicLong(0);
// private AtomicLong dataWritePosition = new AtomicLong(0);
// // 最后一次刷数据的时间
// private long lastFlushTime = System.currentTimeMillis();
// // 上一次刷的文件位置
// private AtomicLong lastFlushFilePosition = new AtomicLong(0);
// // 最大的脏数据量,系统必须触发一次强制刷
// private long MAX_INDEX_BYTE=16;
// private long MAX_FLUSH_DATA_SIZE = 16 *1; // indexsize=16byte 时间和字节共同
// // 最大的时间间隔,系统必须触发一次强制刷
// private long MAX_FLUSH_TIME_GAP = 25; //30ms 因为一次记录写入时间基本在30ms 误差一两条
// RandomAccessFile indexFile, dataFile;
// FileDescriptor indexFileDescriptor;
// FileDescriptor dataFileDescriptor;
// ConcurrentHashMap<String, RandomAccessFile> fileHashMap = new ConcurrentHashMap<String, RandomAccessFile>();
// ConcurrentHashMap<RandomAccessFile, MappedByteBuffer> mappedByteBufferHashMap = new ConcurrentHashMap<RandomAccessFile, MappedByteBuffer>();
// MappedByteBuffer dataMappedByteBuffer, indexMappedByteBuffer;
//
// @Override
// public void init() {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void close() {
// // TODO Auto-generated method stub
// try {
//
// if (indexFile != null) {
// indexFile.close();
// }
// if (dataFile != null) {
// dataFile.close();
// }
//
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// } finally {
//
// }
// }
//
// public synchronized void getPositionForIndexAndData() {
// try {
// // 开始定位到第一条没消费记录
// if (this.indexWritePosition.get() == 0) {
// long i = 0;
// long length = indexFile.length();
// // logger.debug("indexfile.length= " + length);
// while (i < length) {
// // 定位到未读的标示8+4+4
// indexMappedByteBuffer.position((int) (i + 12));
// int temp = indexMappedByteBuffer.getInt();
// if (temp == -1) {
// i += 16;
// continue;
// }
// break;
// }
//
// if (i < 16) {
// this.dataWritePosition.set(0);
// this.indexWritePosition.set(0);
// } else {
// indexMappedByteBuffer.position((int) (i - 16));
// this.dataWritePosition.set(indexMappedByteBuffer.getLong() + indexMappedByteBuffer.getInt());
// this.indexWritePosition.set(i);
// }
//
// logger.debug("this.idnexwirtepostion== ,this.dataWritePostion== " + this.indexWritePosition.get() + ", "
// + this.dataWritePosition.get());
// }
//
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
//
// public synchronized void getMappedByteBuffer(String topicId, String groupId, String consumerId, String queueId) {
// if (topicId == null || topicId.isEmpty()) {
// indexFile = getFile(null, groupId, null, null, StoreConfig.indexFile);
// dataFile = getFile(null, groupId, null, null, StoreConfig.dataFile);
// } else {
// if (consumerId == null || consumerId.isEmpty()) {
// consumerId = groupId;
// }
// indexFile = getFile(topicId, groupId, consumerId, queueId, StoreConfig.indexFile);
// dataFile = getFile(topicId, groupId, consumerId, queueId, StoreConfig.dataFile);
// }
//
// indexMappedByteBuffer = MapedFile(indexFile, 0, MAX_FILE_SIZE);
// dataMappedByteBuffer = MapedFile(dataFile, 0, MAX_FILE_SIZE);
// }
//
// public boolean saveMessage(String topicId, String groupId, String consumerId, String queueId,
// List<byte[]> msgList) {
//
// getMappedByteBuffer(topicId, groupId, consumerId, queueId);
// getPositionForIndexAndData();
// byte[] tempMsg = null;
// for (int i = 0; i < msgList.size(); i++) {
// tempMsg = msgList.get(i);
// // 写入 index
// if (i == 0) {
// indexMappedByteBuffer.position((int) this.indexWritePosition.get());
// }
//
// indexMappedByteBuffer.putLong(this.dataWritePosition.get());
// indexMappedByteBuffer.putInt(tempMsg.length);
// indexMappedByteBuffer.putInt(-1);
// this.indexWritePosition.addAndGet(16);
// // this.indexWritePosition.set(indexMappedByteBuffer.position());
// // 写入data
// if (i == 0) {
// dataMappedByteBuffer.position((int) this.dataWritePosition.get());
// }
//
// dataMappedByteBuffer.put(tempMsg);
// // this.dataWritePosition += msg.length;
// this.dataWritePosition.addAndGet(tempMsg.length);
// // this.dataWritePosition.set(dataMappedByteBuffer.position());
// }
// if (this.dataWritePosition.get() >= MAX_FILE_SIZE || this.indexWritePosition.get() >= MAX_FILE_SIZE) {
// // this.dataWritePosition -= msg.length;
// // this.indexWritePosition -= 16;
// this.dataWritePosition.addAndGet(-(tempMsg.length));
// this.indexWritePosition.addAndGet(-16);
// logger.debug("文件内存空间不够!");
// flush();
// return false;
// }
//
// long st1=System.currentTimeMillis();
// flush();
//
// return true;
//
// }
//
// public boolean saveMessage(String topicId, String groupId, String consumerId, String queueId, byte[] msg) {
//
// getMappedByteBuffer(topicId, groupId, consumerId, queueId);
// getPositionForIndexAndData();
// // 写入 index
// indexMappedByteBuffer.position((int) this.indexWritePosition.get());
// indexMappedByteBuffer.putLong(this.dataWritePosition.get());
// indexMappedByteBuffer.putInt(msg.length);
// indexMappedByteBuffer.putInt(-1);
// this.indexWritePosition.addAndGet(16);
// // 写入data
// dataMappedByteBuffer.position((int) this.dataWritePosition.get());
// dataMappedByteBuffer.put(msg);
// // this.dataWritePosition += msg.length;
// this.dataWritePosition.addAndGet(msg.length);
// if (this.dataWritePosition.get() >= MAX_FILE_SIZE || this.indexWritePosition.get() >= MAX_FILE_SIZE) {
// // this.dataWritePosition -= msg.length;
// // this.indexWritePosition -= 16;
// this.dataWritePosition.addAndGet(-msg.length);
// this.indexWritePosition.addAndGet(-16);
// logger.debug("文件内存空间不够!");
// flush();
// return false;
// }
// flush();
// return true;
//
// }
// CountDownLatch countDownLatch;
// ExecutorService flushPool = Executors.newFixedThreadPool(2);
// public synchronized void flush() {
// countDownLatch=new CountDownLatch(2);
// flushPool.execute(new Thread(){
// @Override
// public void run() {
// // TODO Auto-generated method stub
// // long t1=System.currentTimeMillis();
// try{
// MsgStoreImp_MappedBuffer.this.indexMappedByteBuffer.force();
// }finally{
// countDownLatch.countDown();
// }
// // long t2=System.currentTimeMillis();
// // System.out.println(" force index t2-t1=="+(t2-t1));
// }
// });
// flushPool.execute(new Thread(){
// @Override
// public void run() {
// // TODO Auto-generated method stub
// //long t1=System.currentTimeMillis();
// try{
// MsgStoreImp_MappedBuffer.this.dataMappedByteBuffer.force();
// }finally{
// countDownLatch.countDown();
//
// }
// // long t2=System.currentTimeMillis();
// //System.out.println(" force data t2-t1=="+(t2-t1));
// }
// });
// try {
// countDownLatch.await();
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// // flushPool.shutdown();
// this.lastFlushTime = System.currentTimeMillis();
// this.lastFlushFilePosition = this.indexWritePosition;
// }
//
// @Override
// public boolean writeByteNormal(String topicId, String groupId, String consumerId, String queueId, byte[] msg) {
// // TODO Auto-generated method stub
//
// return saveMessage(topicId, groupId, consumerId, queueId, msg);
//
// }
//
// public boolean writeByteNormal(String topicId, String groupId, String consumerId, String queueId,
// List<byte[]> msgList) {
// // TODO Auto-generated method stub
// return saveMessage(topicId, groupId, consumerId, queueId, msgList);
// }
//
// public synchronized MappedByteBuffer MapedFile(RandomAccessFile raf, long startPos, long fileSize) {
// MappedByteBuffer mappedByteBuffer = mappedByteBufferHashMap.get(raf);
// if (mappedByteBuffer != null) {
// return mappedByteBuffer;
// }
// try {
// FileChannel fileChannel = raf.getChannel();
// mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, startPos, fileSize);
// /*TotalMapedVitualMemory.addAndGet(fileSize);
// TotalMapedFiles.incrementAndGet();*/
// } catch (Exception e) {
// logger.debug("内存映射沒有建立");
// e.printStackTrace();
// }
// mappedByteBufferHashMap.put(raf, mappedByteBuffer);
// return mappedByteBuffer;
// }
//
// private RandomAccessFile getFile(String topicId, String groupId, String consumerId, String queueId,
// String fileName) {
// String file;
// if (topicId == null || topicId.isEmpty()) {
// file = StoreConfig.baseDir + StoreConfig.retryDir + groupId + "/" + fileName;
// } else {
// file = StoreConfig.baseDir + StoreConfig.normalDir + topicId + "/" + groupId + "/" + consumerId + "/"
// + queueId + "/" + fileName;
// }
// // 查找hashmap
// RandomAccessFile raf = fileHashMap.get(file);
// if (raf != null) {
// return raf;
// }
// File f = new File(file);
// try {
// if (!f.exists()) {
// if (!f.getParentFile().exists()) {
// f.getParentFile().mkdirs();
// }
// f.createNewFile();
// }
// raf = new RandomAccessFile(f, "rw");
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// fileHashMap.put(file, raf);
// return raf;
// }
//
// /*
// * 根据请求参数传回List<Message>
// *
// *
// */
// public ArrayList<byte[]> getMessage(String topicId, String groupId, String consumerId, String queueId, int offset,
// int maxOffset) {
// ArrayList<byte[]> resultList = new ArrayList<byte[]>();
// if (topicId == null || topicId.isEmpty()) {
// indexFile = getFile(null, groupId, null, null, StoreConfig.indexFile);
// dataFile = getFile(null, groupId, null, null, StoreConfig.dataFile);
// } else {
// if (consumerId == null || consumerId.isEmpty()) {
// consumerId = groupId;
// }
// indexFile = getFile(topicId, groupId, consumerId, queueId, StoreConfig.indexFile);
// dataFile = getFile(topicId, groupId, consumerId, queueId, StoreConfig.dataFile);
// }
//
// long len = 0;
// try {
// len = indexFile.length() / 16;
// } catch (IOException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
//
// while (offset <= maxOffset && offset < len) {
// // long+int+int =16
// try {
// int indexoffset = offset * 16;
// indexFile.seek(indexoffset);
// long dataOffset = indexFile.readLong();
// int dataSize = indexFile.readInt();
// // 根据dataoffset读出 msg
// dataFile.seek(dataOffset);
// byte[] msgBody = new byte[dataSize];
// dataFile.read(msgBody);
// // 读出内容将index文件的type类型设置为已经读“1”
// indexFile.seek(indexoffset + 12);
// indexFile.writeInt(1);
// resultList.add(msgBody);
// offset += 1;
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// return resultList;
// }
// }
//
// return resultList;
//
// }
//
// @Override
// public ArrayList<byte[]> readByteNormal(String topicId, String groupId, String consumerId, String queueId,
// int offset, int maxOffset) {
// // TODO Auto-generated method stub
// return getMessage(topicId, groupId, consumerId, queueId, offset, maxOffset);
//
// }
//
// @Override
// public boolean writeByteRetry(String groupId, byte[] msg) {
// // TODO Auto-generated method stub
// return saveMessage(null, groupId, null, null, msg);
// }
//
// @Override
// public ArrayList<byte[]> readByteRetry(String groupId, int offset, int maxOffset) {
//
// return getMessage(null, groupId, null, null, offset, maxOffset);
//
// }
//
// public static void main(String[] args) {
//
// }
//
// @Override
// public List<byte[]> readByteByOffsets(String topicID, String group,
// String consumer, String queueID, Integer[] offsets) {
// // TODO Auto-generated method stub
// return null;
// }
//}

View File

@@ -0,0 +1,239 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* baseDir/Normal/Topic/Group/Consumer/Queue/(index.file,data.file)
* baseDir/Retry/Group/(index.file,data.file)
* 题目没有consumerID就默认生成和groupID一样的
* */
public class MsgStoreImp_MappedBuffer2 implements MsgStore {
private static Logger logger = LoggerFactory
.getLogger(MsgStoreImp_MappedBuffer2.class);
private static ConcurrentHashMap<String, FileStoreManager> fileStoreManagerMap = new ConcurrentHashMap<String, FileStoreManager>();
@Override
public void init() {
// TODO Auto-generated method stub
}
@Override
public void close() {
// TODO Auto-generated method stub
fileStoreManagerMap.clear();
}
@Override
public boolean writeByteNormal(String topicId, String queueId,
List<byte[]> msgList) {
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.normalDir + topicId
+ "/" + queueId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
logger.debug("建立filestoremanager= " + filePath);
}
return fileStoreManager.saveMessage(msgList);
}
@Override
public void testprintlong() {
System.out.println("FileStoreManager.savemessage"
+ FileStoreManager.savemessage);
System.err.println("FileStoreManager.savemessagebyonce"
+ FileStoreManager.savemessagebyonce);
}
@Override
public boolean writeByteNormalByOnce(String topicId, String queueId,
List<byte[]> msgList) {
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.normalDir + topicId
+ "/" + queueId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
logger.debug("建立filestoremanager= " + filePath);
}
return fileStoreManager.saveMessageByOnce(msgList);
}
@Override
public boolean writeByteRetry(String groupId, List<byte[]> msgList) {
// TODO Auto-generated method stub
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.retryDir + groupId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
}
return fileStoreManager.saveMessage(msgList);
}
@Override
public boolean writeByteRetryByOnce(String groupId, List<byte[]> msgList) {
// TODO Auto-generated method stub
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.retryDir + groupId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
}
return fileStoreManager.saveMessageByOnce(msgList);
}
@Override
public ArrayList<byte[]> readByteRetry(String groupId, int offset,
int MaxOffset) {
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.retryDir + groupId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
}
return (ArrayList) fileStoreManager.getMessage(offset, MaxOffset);
}
@Override
public List<byte[]> readByteNormal(String topicId, String queueId,
int offset, int MaxOffset) {
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.normalDir + topicId
+ "/" + queueId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
logger.debug("读数据建立filestoremanage");
}
logger.debug("读数据的起始地址为" + offset + " " + MaxOffset);
return (ArrayList) fileStoreManager.getMessage(offset, MaxOffset);
}
@Override
public List<byte[]> readByteNormalByOnce(String topicId, String queueId,
int offset, int MaxOffset) {
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.normalDir + topicId
+ "/" + queueId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
logger.debug("读数据建立filestoremanage");
}
logger.debug("读数据的起始地址为" + offset + " " + MaxOffset);
return (ArrayList) fileStoreManager.getMessageByOnce(offset, MaxOffset);
}
@Override
public List<byte[]> readByteRetryByOnce(String queueId, int offset,
int MaxOffset) {
// 存储文件路径
String filePath = StoreConfig.baseDir + StoreConfig.normalDir + "/"
+ queueId;
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath);
fileStoreManagerMap.put(filePath, fileStoreManager);
logger.debug("读数据建立filestoremanage");
}
logger.debug("读数据的起始地址为" + offset + " " + MaxOffset);
return (ArrayList) fileStoreManager.getMessageByOnce(offset, MaxOffset);
}
@Override
public void writeMappedFileTemp(String filename) {
// TODO Auto-generated method stub
}
@Override
public void loadAndRecover() {
// 恢复正常消息队列
String filePath = StoreConfig.baseDir + StoreConfig.normalDir;
ArrayList<String[]> rsPath = this.scanFilePathForNormal(filePath);
if (rsPath == null)
return;
for (String[] path : rsPath) {
// 存储文件路径
logger.error(filePath.toString());
filePath = StoreConfig.baseDir + StoreConfig.normalDir+path[0] + "/" + path[1];
logger.error(filePath.toString());
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap
.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath, "testrecover");
fileStoreManagerMap.put(filePath, fileStoreManager);
}
}
// 恢复订阅关系
filePath = StoreConfig.baseDir + StoreConfig.subscribeDir;
logger.error("subFfilepath="+filePath);
FileStoreManager fileStoreManager = fileStoreManagerMap.get(filePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(filePath, "testrecover");
fileStoreManagerMap.put(filePath, fileStoreManager);
}
//恢复retry关系
//filePath = StoreConfig.baseDir + StoreConfig.;
}
public ArrayList<String[]> scanFilePathForNormal(String filePath) {
ArrayList<String[]> path = new ArrayList<String[]>();
File[] fileList = new File(filePath).listFiles();
if (fileList == null)
return null;
for (File tempFile : fileList) {
if (tempFile.isDirectory()) {
for (File temp : tempFile.listFiles()) {
String[] tq = new String[2];
String fs = System.getProperty("file.separator");
System.out.println(temp.toString() + " fs= " + fs);
String t = temp.toString();
int i = t.lastIndexOf(fs);
tq[1] = t.substring(i + 1);
int j = t.lastIndexOf(fs, i - 1);
tq[0] = t.substring(j + 1, i);
System.out.println(i + "-----" + j);
path.add(tq);
}
}
}
for (String[] t : path) {
System.out.println(t[0] + " / " + t[1]);
}
return path;
}
}

View File

@@ -0,0 +1,21 @@
package com.alibaba.middleware.race.mom.store;
import java.io.Serializable;
public class OffsetNum implements Serializable {
/**
* offset 的数值
*/
private static final long serialVersionUID = -352056806960750564L;
int i;
public int getI() {
return i;
}
public OffsetNum setI(int i) {
this.i = i;
return this;
}
public String toString(){
return String.valueOf(i);
}
}

View File

@@ -0,0 +1,133 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import com.alibaba.fastjson.JSON;
public class Redo {
public static String redoFile = System.getProperty("user.home")
+ File.separator +"0";
public MappedByteBuffer mbb;
public File file;
public RandomAccessFile raf;
public AtomicLong filename = new AtomicLong(1);
public int filesize = 1024*1024 * 1024;
private RedoBean rb=new RedoBean();
public void writeLog(String msgid,String topicAndfilter,byte[] body)
{
rb.getBody().add(body);
rb.getMsgId().add(msgid);
rb.getTopicAfilter().add(topicAndfilter);
}
public void commitLog(RedoBean rb) {
byte[] smByte = JSON.toJSONBytes(rb);
if (mbb.position() + smByte.length > filesize) {
filename.getAndIncrement();
try {
mbb = new RandomAccessFile(getNewFile(), "rw").getChannel().map(
FileChannel.MapMode.READ_WRITE, 0, filesize);;
} catch (IOException e) {
}
}
mbb.putInt(smByte.length);
mbb.put(smByte);
}
public void flushLog() {
commitLog(rb);
mbb.force();
rb=new RedoBean();
}
public Redo() {
file = new File(redoFile);
ensureDirOK(file.getParent());
RandomAccessFile raf;
try {
raf = new RandomAccessFile(file, "rw");
FileChannel fileChannel = raf.getChannel();
mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, filesize);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public File getNewFile() throws FileNotFoundException,
IOException {
String newfilename = new String(""
+ (Long.parseLong(file.getName()) + filesize));
file = new File(System.getProperty("user.home") + File.separator
+ "store" + File.separator + newfilename);
return file;
}
public static void main(String args[]) throws IOException {
for(int j=0;j<100;j++)
{
Redo redo = new Redo();
long begin=System.currentTimeMillis();
for(int i=0;i<200;i++)
{
redo.writeLog("msg-"+i, "topic-and-filter-y", "hello mom I'm body".getBytes());
}
redo.flushLog();
System.out.println(System.currentTimeMillis()-begin);
}
}
public void ensureDirOK(final String dirName) {
if (dirName != null) {
File f = new File(dirName);
if (!f.exists()) {
f.mkdirs();
}
}
}
class RedoBean implements Serializable{
/**
* 存储的实体
*/
private static final long serialVersionUID = -5597911942382576497L;
List<String> topicAfilter=new ArrayList<>();
List<String> msgId=new ArrayList<>();
List<byte[]> body=new ArrayList<>();
public List<String> getTopicAfilter() {
return topicAfilter;
}
public void setTopicAfilter(List<String> topicAfilter) {
this.topicAfilter = topicAfilter;
}
public List<String> getMsgId() {
return msgId;
}
public void setMsgId(List<String> msgId) {
this.msgId = msgId;
}
public List<byte[]> getBody() {
return body;
}
public void setBody(List<byte[]> body) {
this.body = body;
}
}
}

View File

@@ -0,0 +1,163 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import com.alibaba.fastjson.JSON;
public class RedoLog {
private static String redoFile = StoreConfig.baseDir
+ "oo33o" + "r2222edo";
public MappedByteBuffer mbb;
public int fileSize = repeatNum*(msgSize+1);
public static int repeatNum = 512;
public static int msgSize = 64;
public char FLAG = 0;
//god bless
public RedoLog() {
this.mbb = this.getFileMappedByteBuffer(redoFile, 0, fileSize);
}
// msg=head +body :
public boolean writeLog(String topic, String filter, int queueIndex,
ArrayList<byte[]> bodys) {
// LogBean lb=new LogBean(topic, filter, 0,bodys);
// byte[] data=JSON.toJSONBytes(lb);
for (int i = 0; i < bodys.size(); i++) {
String head = topic + FLAG + filter + FLAG + queueIndex;
byte[] headByte = head.getBytes();
// head.size head body.szie body
ByteBuffer msgByteBuffer = ByteBuffer.allocate(msgSize);
msgByteBuffer.putInt(headByte.length);
msgByteBuffer.put(headByte);
msgByteBuffer.putInt(bodys.get(i).length);
msgByteBuffer.put(bodys.get(i));
boolean flag = this.writeLog(msgByteBuffer);
if (!flag) {
return false;
}
}
return true;
//this.flushLog();
}
private boolean writebytes(byte[] smByte)
{
if (mbb.position() + smByte.length > fileSize) {
return false;
}
mbb.putInt(smByte.length);
mbb.put(smByte);
return true;
}
private boolean writeLog(ByteBuffer smByte) {
if (mbb.position() + smByte.limit() > fileSize) {
return false;
}
mbb.putInt(smByte.limit());
smByte.flip();
mbb.put(smByte);
return true;
}
public void flushLog() {
mbb.force();
if (mbb.position() > repeatNum * msgSize)
mbb.position(0);
}
private MappedByteBuffer getFileMappedByteBuffer(String filePathAndName,
int startPos, int fileSize) {
File f = new File(filePathAndName);
try {
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
}
return mbb = new RandomAccessFile(f, "rw").getChannel().map(
MapMode.READ_WRITE, startPos, fileSize);
} catch (Exception e) {
return null;
}
}
public static void main(String args[]) throws IOException {
RedoLog redo = new RedoLog();
char FLAG = 0;
for (int j = 0; j < 500; j++) {
long begin = System.currentTimeMillis();
for (int i = 0; i < 200; i++) {
/*
* String data = "topic" + i + FLAG + "fitler" + FLAG +
* "hello mom Im baby"; ByteBuffer smByte =
* ByteBuffer.allocate(redo.msgSize);
* smByte.put(data.getBytes()); redo.writeLog(smByte);
*/
ArrayList<byte[]> list = new ArrayList<byte[]>();
list.add("1234".getBytes());
redo.writeLog("topic", "filter", 0, list);
}
long flushtime = System.currentTimeMillis();
redo.flushLog();
System.out.println("writetime:" + (flushtime - begin)
+ " flushtime:" + (System.currentTimeMillis() - flushtime));
}
}
class LogBean
{
String topic;
String filter;
int queueid;
ArrayList<byte[]> list=new ArrayList<>();
public LogBean(String topic, String filter, int queueid, ArrayList<byte[]> list) {
super();
this.topic = topic;
this.filter = filter;
this.queueid = queueid;
this.list = list;
}
public int getQueueid() {
return queueid;
}
public void setQueueid(int queueid) {
this.queueid = queueid;
}
public LogBean(String topic, String filter, ArrayList<byte[]> list) {
super();
this.topic = topic;
this.filter = filter;
this.list = list;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getFilter() {
return filter;
}
public void setFilter(String filter) {
this.filter = filter;
}
public ArrayList<byte[]> getList() {
return list;
}
public void setList(ArrayList<byte[]> list) {
this.list = list;
}
}
}

View File

@@ -0,0 +1,28 @@
package com.alibaba.middleware.race.mom.store;
public class StoreConfig {
// 主目录
public static String fileRoot = System.getProperty("user.home");
// public static String fileSpt = System.getProperty("file.separator");
public static String baseDir = fileRoot + "/store/";
// 正常消息文件
public static String normalDir = "normal/";
// 重试消息文件
public static String retryDir = "retry/";
// 订阅关系
public static String subscribeDir = "subscribe/";
//
public static String arrayDir = "array/";
// 索引文件名
/*
* 默认 offset(8byte) size(4byte) extra(4byte)
*/
public static int offsetByte = 8, sizeByte = 4, extraByte = 4;
public static String indexFile = "index.file";
// 消息文件名
public static String dataFile = "data.file";
// 订阅关系文件名
public static String subDataFile = "subData.file";
public static String subIndexFile = "subIndex.file";
}

View File

@@ -0,0 +1,21 @@
package com.alibaba.middleware.race.mom.store;
import java.io.Serializable;
public class StoreMsg implements Serializable{
/**
*
*/
private static final long serialVersionUID = -2571744737752908548L;
String id;
String topic;
int queueid;
byte[] body;
public StoreMsg(String id, String topic, int queueid, byte[] body) {
this.id = id;
this.topic = topic;
this.queueid = queueid;
this.body = body;
}
}

View File

@@ -0,0 +1,16 @@
package com.alibaba.middleware.race.mom.store;
import java.util.ArrayList;
import com.alibaba.middleware.race.mom.broker.function.Offset;
/*
* by ChenQi
* 订阅关系持久化
* */
public interface SubscribeStore {
//读出所有的订阅关系
public ArrayList<Offset> read();
//存所有的订阅关系
public boolean write(ArrayList<Offset> subInfoList);
}

View File

@@ -0,0 +1,134 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import com.alibaba.fastjson.JSON;
import com.alibaba.middleware.race.mom.broker.function.Offset;
public class SubscribeStoreImp implements SubscribeStore {
@Override
public ArrayList<Offset> read() {
// TODO Auto-generated method stub
ArrayList<Offset> rs = new ArrayList<Offset>();
RandomAccessFile subIndexFile = getSubFile(StoreConfig.subIndexFile, false);
RandomAccessFile subDataFile = getSubFile(StoreConfig.subDataFile, false);
try {
long indexLength = subIndexFile.length();
long index = 0;
long dataPos = 0;
int dataSize = 0;
byte[] subByte;
while (index < indexLength) {
subIndexFile.seek(index);
dataPos = subIndexFile.readLong();
dataSize = subIndexFile.readInt();
subDataFile.seek(dataPos);
subByte = new byte[dataSize];
subDataFile.read(subByte);
rs.add(((Offset) JSON.parseObject(subByte, Offset.class)));
index += 16;
}
} catch (Exception e) {
e.printStackTrace();
return rs;
}finally{
try {
subIndexFile.close();
subDataFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return rs;
}
@Override
public boolean write(ArrayList<Offset> subInfoList) {
// TODO Auto-generated method stub
RandomAccessFile subIndexFile = getSubFile(StoreConfig.subIndexFile, true);
RandomAccessFile subDataFile = getSubFile(StoreConfig.subDataFile, true);
try {
long dataPos = 0;
long indexPos = 0;
// 每次重头写
for (Offset sb : subInfoList) {
indexPos = subIndexFile.length();
dataPos = subDataFile.length();
// 写入index
subIndexFile.seek(indexPos);
subIndexFile.writeLong(dataPos);
byte[] sbByte = JSON.toJSONBytes(sb);
subIndexFile.writeInt(sbByte.length);
subIndexFile.writeInt(0);
// 写入data
subDataFile.seek(dataPos);
subDataFile.write(sbByte);
System.out.println("indexpos,datapos=" + subIndexFile.length() + "," + subDataFile.length());
}
} catch (Exception e) {
e.printStackTrace();
return false;
}finally{
try {
subIndexFile.close();
subDataFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return true;
}
public RandomAccessFile getSubFile(String fileName, boolean isWriteMethod) {
String file;
RandomAccessFile raf = null;
file = StoreConfig.baseDir + StoreConfig.subscribeDir + fileName;
System.out.println("file=" + file);
File f = new File(file);
if (isWriteMethod) {
try {
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
} else {
// 删除老文件
f.delete();
f.createNewFile();
}
raf = new RandomAccessFile(f, "rw");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
try {
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
}
raf = new RandomAccessFile(f, "rw");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return raf;
}
}

View File

@@ -0,0 +1,67 @@
package com.alibaba.middleware.race.mom.store;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.middleware.race.mom.broker.function.Offset;
public class SubscribeStoreImp_MappedBuffer2 implements SubscribeStore {
private static Logger logger = LoggerFactory
.getLogger(SubscribeStoreImp_MappedBuffer2.class);
private static String subscribeFilePath = StoreConfig.baseDir
+ StoreConfig.subscribeDir;
private static ConcurrentHashMap<String, FileStoreManager> fileStoreManagerMap = new ConcurrentHashMap<String, FileStoreManager>();
@Override
public ArrayList<Offset> read() {
FileStoreManager fileStoreManager = fileStoreManagerMap
.get(subscribeFilePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(subscribeFilePath);
// 为恢复
fileStoreManagerMap.put(subscribeFilePath, fileStoreManager);
}
return (ArrayList<Offset>) fileStoreManager.getSubscribe();
}
@Override
public boolean write(ArrayList<Offset> subInfoList) {
// 对应的文件管理器
FileStoreManager fileStoreManager = fileStoreManagerMap
.get(subscribeFilePath);
if (fileStoreManager == null) {
fileStoreManager = new FileStoreManager(subscribeFilePath);
// 为恢复
fileStoreManagerMap.put(subscribeFilePath, fileStoreManager);
}
// 将写位置重置为16
fileStoreManager.resetFilePosition();
ArrayList<byte[]> dataList = new ArrayList<byte[]>(subInfoList.size());
int count = 1;
for (Offset tmp : subInfoList) {
logger.debug("保存订阅关系 i+== " + (count++) + " , " + tmp.getTopic());
dataList.add(JSON.toJSONBytes(tmp));
}
//return fileStoreManager.saveMessage(dataList);
return fileStoreManager.saveMessageByOnce(dataList);
}
/*
* private void deleteOldSubscribeFile() { deleteFile(subscribeFilePath +
* "/index/0", true); deleteFile(subscribeFilePath + "/data/0", true); }
*
* public void deleteFile(String file, boolean isWriteOverride) { File f =
* new File(file); if (isWriteOverride) { try { if (f.exists()) { // 删除老文件
* f.delete(); } } catch (Exception e) { // TODO Auto-generated catch block
* logger.error(e.getMessage()); } } }
*/
}

View File

@@ -0,0 +1,231 @@
//package com.alibaba.middleware.race.mom.store;
//
//import java.io.File;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Random;
//import java.util.concurrent.BlockingQueue;
//import java.util.concurrent.LinkedBlockingQueue;
//
//import com.alibaba.fastjson.JSON;
//import com.alibaba.middleware.race.mom.Message;
//import com.alibaba.middleware.race.mom.broker.function.Offset;
//
//public class Test {
// String topic = "topic1", group = "group1", consumer = "group1";
// int queue = 0;
// BlockingQueue<Message> q = new LinkedBlockingQueue<>();
// // 进度
// int offset = 0, maxoffset = 9;
//
// static class Msg {
// String a = "a";
// int b = 3;
// }
//
// public static void main(String args[]) {
// Test t = new Test();
// // 内存测试
// // t.init();
// // t.show();
// // 存储恢复测试
// // t.q.clear();
// // t.init();
// // t.store();
// // t.recover();
// // t.q.clear();
//
// // t.init();
// /*
// * t.store2_new(); t.recover2_new();
// */
// t.q.clear();
// t.init();
// t.store2byonce();
// t.recover2();
//
// // t.testSub();
// // t.testArrayList();
// t.testFile2();
// //t.testFile();
// //t.scanFilePath(StoreConfig.baseDir+StoreConfig.subscribeDir);
// }
//
// public void testFile2() {
// mstore2.loadAndRecover();
// }
//
// public void testFile() {
// // 对正常消息
// String filePath = StoreConfig.baseDir + StoreConfig.normalDir;
// ArrayList<String[]> rsPath=this.scanFilePathForNormal(filePath);
// for(String[] path:rsPath){
// System.out.println();
// }
// filePath=StoreConfig.baseDir + StoreConfig.subscribeDir;
// System.out.println(filePath);
// String[] rs=scanFilePath(filePath);
// }
//
// public String[] scanFilePath(String filePath) {
// ArrayList<String> path = new ArrayList<String>();
// String[] fileList = new File(filePath).list();
// if (fileList == null)
// {
// System.out.println("null");
// return null;
// }
//
//
// for (String t : fileList) {
// System.out.println(t);
// }
// return fileList;
// }
// public ArrayList<String[]> scanFilePathForNormal(String filePath) {
// ArrayList<String[]> path = new ArrayList<String[]>();
// File[] fileList = new File(filePath).listFiles();
// for (File tempFile : fileList) {
// if (tempFile.isDirectory()) {
// for (File temp : tempFile.listFiles()) {
// String[] tq = new String[2];
// String fs = System.getProperty("file.separator");
// System.out.println(temp.toString() + " fs= " + fs);
// String t = temp.toString();
// int i = t.lastIndexOf(fs);
// tq[1] = t.substring(i + 1);
// int j = t.lastIndexOf(fs, i - 1);
// tq[0] = t.substring(j + 1, i);
// System.out.println(i + "-----" + j);
// path.add(tq);
// }
// }
// }
// for (String[] t : path) {
// System.out.println(t[0] + " / " + t[1]);
// }
// return path;
// }
//
// public void show() {
// // 显示
// for (int i = 0; i < 10; i++) {
// Message m = q.poll();
// if (i < offset)
// System.out.println("已消费:" + m.getMsgId());
// else
// System.out.println("未消费:" + m.getMsgId());
// }
// }
//
// MsgStore mstore2 = new MsgStoreImp_MappedBuffer2();
//
// public void store2() {
//
// List<byte[]> msgList = new ArrayList<byte[]>(10);
// for (int i = 0; i < 10; i++) {
// Message msg = q.poll();
// byte[] msgbyte = JSON.toJSONBytes(msg);// 这里用fjson序列化一下
// msgList.add(msgbyte);
// }
// long startTime = System.currentTimeMillis();
// mstore2.writeByteNormal(topic, queue + "", msgList);
// long endTime = System.currentTimeMillis();
// System.out.println("写入msgList数据时间 endTime-StartTime="
// + (endTime - startTime));
// }
//
//
// public void store2byonce() {
//
// List<byte[]> msgList = new ArrayList<byte[]>(10);
// for (int i = 0; i < 10; i++) {
// Message msg = q.poll();
// byte[] msgbyte = JSON.toJSONBytes(msg);// 这里用fjson序列化一下
// msgList.add(msgbyte);
// }
// long startTime = System.currentTimeMillis();
// mstore2.writeByteNormalByOnce(topic, queue + "", msgList);
// long endTime = System.currentTimeMillis();
// System.out.println("写入msgList数据时间 endTime-StartTime="
// + (endTime - startTime));
// }
//
// public void recover2() {
// long startTime = System.currentTimeMillis();
// ArrayList<byte[]> blist = (ArrayList<byte[]>) mstore2.readByteNormal(
// topic, queue + "", offset, maxoffset);
// long endTime = System.currentTimeMillis();
// System.out.println(" 读出数据时间 endTime-StartTime="
// + (endTime - startTime));
//
// for (byte[] b : blist) {
// Message msg = JSON.parseObject(b, Message.class);// obj 把 byte转为对象
// System.out.println("未消费:" + msg.getMsgId());
// }
// }
//
//
// public void init() {
// // queue: 头-> 0 1 2 3 4(offset) 5 6 7 8 9(maxoffset)
// for (int i = 0; i < 10; i++) {
// Message msg = new Message();
// msg.setTopic(topic);
// msg.setBornTime(System.currentTimeMillis());
// msg.setBody(new String("测试哦" + new Random().nextLong()).getBytes());
// System.out.println("init msg id " + msg.getMsgId());
// q.add(msg);
// }
// }
//
// public void destory() {
// mstore2.close();
// }
//
// public void testSub() {
// // Offset sb1 = new Offset();
// // sb1.setTopicId("MOM-RACE-21486");
// // sb1.setGroupId("CID_21486");
// // sb1.setQueueId("0");
// // sb1.setCurrentoffset(1);
// // sb1.setCacheOffset(1);
// // sb1.setMaxOffset(1);
// // Offset sb2 = new Offset();
// // sb2.setTopicId("ccc");
// // sb2.setGroupId("dfadfasdlfasdfas");
// // System.out.println("size(sb1):" + (JSON.toJSONBytes(sb1)).length);
// // System.out.println("size(sb2):" + (JSON.toJSONBytes(sb2)).length);
// SubscribeStoreImp_MappedBuffer2 ssi = new SubscribeStoreImp_MappedBuffer2();
// ArrayList<Offset> ls = new ArrayList<Offset>();
//
// // ls.add(sb1);
// // ls.add(sb2);
// // ssi.write(ls);
// System.out.println("开始读出订阅关系");
// ls = ssi.read();
// for (Offset sb : ls) {
// System.out.println(sb.toString());
// }
//
// }
//
// public void testArrayList() {
// OffsetNum sb1 = new OffsetNum();
// sb1.setI(1111);
// OffsetNum sb2 = new OffsetNum();
// sb2.setI(22222);
// System.out.println("size(sb1):" + (JSON.toJSONBytes(sb1)).length);
// System.out.println("size(sb2):" + (JSON.toJSONBytes(sb2)).length);
// ArrayStoreImp ssi = new ArrayStoreImp();
// ArrayList<OffsetNum> ls = new ArrayList<OffsetNum>();
//
// ls.add(sb1);
// ls.add(sb2);
// ssi.store(ls, "topicAndFilter", "0");
// System.out.println("开始读出订阅关系");
// ls = ssi.recover("topicAndFilter", "0");
// for (OffsetNum sb : ls) {
// System.out.println(sb.i);
// }
// }
//}

View File

@@ -0,0 +1,143 @@
package com.alibaba.middleware.race.mom.store;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel.MapMode;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class redotest {
String redoFile = System.getProperty("user.home") + File.separator
+ "store";
public MappedByteBuffer mbb;
public File file;
public AtomicInteger fileName = new AtomicInteger(0);
public int filesize = 1024*1024;
BlockingQueue<MappedByteBuffer> mmbStoreQue = new ArrayBlockingQueue<MappedByteBuffer>(
10);
BlockingQueue<MappedByteBuffer> mmbRecoverQue = new ArrayBlockingQueue<MappedByteBuffer>(
10);
public void writeLog2(ByteBuffer smByte) {
if (mbb.position() + smByte.limit() > filesize) {
try {
mmbRecoverQue.put(this.mbb);
this.mbb = this.mmbStoreQue.poll(3, TimeUnit.MILLISECONDS);
if (this.mbb == null) {
this.createMbb();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// ByteBuffer by = ByteBuffer.allocate(smByte.length);
mbb.putInt(smByte.limit());
mbb.put(smByte);
}
public void readRecoverLog2() {
MappedByteBuffer readMbb = null;
while (mmbRecoverQue.size() != 0) {
try {
readMbb = this.mmbRecoverQue.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 恢复数据
int size = readMbb.getInt();
while (size != 0) {
byte[] msg = new byte[size];
readMbb.get(msg);
{
// 开始写indexdata文件
}
size = readMbb.getInt();
}
}
}
public void flushLog() {
mbb.force();
}
public redotest() {
this.createMbb();
}
private void createMbb() {
for (int i = 0; i < 10; i++) {
try {
mmbStoreQue.put(getFileMappedByteBuffer(redoFile
+ File.separator + fileName.getAndIncrement(), 0,
filesize));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
this.mbb = mmbStoreQue.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private MappedByteBuffer getFileMappedByteBuffer(String filePathAndName,
int startPos, int fileSize) {
File f = new File(filePathAndName);
try {
if (!f.exists()) {
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
}
f.createNewFile();
}
return mbb = new RandomAccessFile(f, "rw").getChannel().map(
MapMode.READ_WRITE, startPos, fileSize);
} catch (Exception e) {
return null;
}
}
/*
* public MappedByteBuffer getNewFile() throws FileNotFoundException,
* IOException { String newfilename = new String("" +
* (Long.parseLong(file.getName()) + filesize)); file = new
* File(System.getProperty("user.home") + File.separator + "store" +
* File.separator + newfilename); mbb = new RandomAccessFile(file,
* "rw").getChannel().map( FileChannel.MapMode.READ_WRITE, 0, filesize);
* return mbb; }
*/
public static void main(String args[]) throws IOException {
final redotest redo = new redotest();
char FLAG=0;
for(int j=0;j<500;j++)
{
final long begin = System.currentTimeMillis();
for (int i = 0; i < 200; i++) {
String data="topic"+i+FLAG+"fitler"+FLAG+"hello mom Im baby";
ByteBuffer smByte=ByteBuffer.allocate(64);
smByte.put(data.getBytes());
redo.writeLog2(smByte);
}
long flushtime=System.currentTimeMillis();
redo.flushLog();
System.out.println("writetime:"+(flushtime-begin)+" flushtime:"
+ (System.currentTimeMillis() - flushtime));
}
}
}

View File

@@ -0,0 +1,36 @@
package com.alibaba.middleware.race.mom.util;
import io.netty.channel.Channel;
import java.net.SocketAddress;
public class ConsumerInfo {
private Channel channel;
private SocketAddress consumerAddress;
public ConsumerInfo(Channel channel){
this.channel=channel;
this.consumerAddress=channel.remoteAddress();
}
public Channel channel() {
return channel;
}
public SocketAddress consumerAddress() {
return consumerAddress;
}
@Override
public boolean equals(Object obj) {
if(this==obj){
return true;
}else if(obj instanceof ConsumerInfo){
ConsumerInfo another=(ConsumerInfo)obj;
return this.consumerAddress.equals(another.consumerAddress);
}else return false;
}
}

View File

@@ -0,0 +1,37 @@
package com.alibaba.middleware.race.mom.util;
import java.io.Serializable;
/*
* 封装所有的请求和响应信息
* type 请求或者响应类型
* body 对应的数据
* describle 类型描述信息
* Author ilyy510
* */
public class Info implements Serializable{
/**
*
*/
private static final long serialVersionUID = -2529148421210651297L;
InfoType type;
byte[] body;
public InfoType getType() {
return type;
}
public void setType(InfoType type) {
this.type = type;
}
public byte[] getBody() {
return body;
}
public void setBody(byte[] body) {
this.body = body;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}

View File

@@ -0,0 +1,36 @@
package com.alibaba.middleware.race.mom.util;
import java.io.Serializable;
import java.util.Map;
public class InfoBodyConsumer implements Serializable{
/**
*
*/
private static final long serialVersionUID = 4500208867228323993L;
private String groupId;
private String topic;
private Map<String,String> filterMap;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public Map<String, String> getFilterMap() {
return filterMap;
}
public void setFilterMap(Map<String, String> filterMap) {
this.filterMap = filterMap;
}
public String toString(){
return "group:"+this.groupId+" topic:"+this.topic+" filter:"+this.filterMap;
}
}

View File

@@ -0,0 +1,28 @@
package com.alibaba.middleware.race.mom.util;
import java.io.Serializable;
import java.util.ArrayList;
import com.alibaba.middleware.race.mom.broker.function.MessageInfo;
/**
*
* @author Administrator
* 封装producer的请求信息
*/
public class InfoBodyProduceList implements Serializable{
private static final long serialVersionUID = 9075042672715185764L;
ArrayList<MessageInfo> msglist=new ArrayList<>();
public ArrayList<MessageInfo> getMsglist() {
return msglist;
}
public void setMsglist(ArrayList<MessageInfo> msglist) {
this.msglist = msglist;
}
public InfoBodyProduceList() {
}
}

View File

@@ -0,0 +1,12 @@
package com.alibaba.middleware.race.mom.util;
/**
* Info消息的类型说明
* Author ilyy510
* */
public enum InfoType {
PRODUCER_TO_BROKER_SENG_MESSAGE,
BROKER_TO_PRODUCER_CONFIRM_MESSAGE,
BROKER_TO_CONSUMER_PUSH_MESSAGE,
CONSUMER_TO_BROKER_CONFIRM_MESSAGE,
CONSUMER_TO_BROKER_CONNECT
}

View File

@@ -0,0 +1,21 @@
package com.alibaba.middleware.race.mom.util;
public class InfoUtil {
public static byte[] arraycat(byte[] buf1,byte[] buf2)
{
byte[] bufret=null;
int len1=0;
int len2=0;
if(buf1!=null)
len1=buf1.length;
if(buf2!=null)
len2=buf2.length;
if(len1+len2>0)
bufret=new byte[len1+len2];
if(len1>0)
System.arraycopy(buf1,0,bufret,0,len1);
if(len2>0)
System.arraycopy(buf2,0,bufret,len1,len2);
return bufret;
}
}

View File

@@ -0,0 +1,87 @@
package com.alibaba.middleware.race.mom.util;
import java.io.Serializable;
import java.util.Map;
/**
* topic and filter的封装,一种TopicAndFilter代表一种消息,来自同一生产者集群组
* 订阅者集群组 订阅某一TopicAndFilter(注意,订阅者filter为null,则订阅topic下所有filter消息)
* 使用注意:构建订阅者TopicAndFilter须根据订阅者信息; 构建生产者或消息的TopicAndFilter须根据生产者的信息(系统大量使用TopicAndFilter为map键,构建绝对不能出错)
* @author youngforever
*
*/
public class TopicAndFilter implements Serializable{
private static final long serialVersionUID = -7983983900930009841L;
private String topic;
private Map<String,String> filter;
public TopicAndFilter(){};
public TopicAndFilter(String topic, Map<String,String> filter) {
if (topic == null) {
throw new IllegalArgumentException("Left value is not effective.");
}
//允许filter为null
// if (filter == null) {
// throw new IllegalArgumentException("Right value is not effective.");
// }
this.topic = topic;
this.filter = filter;
}
// public TopicAndFilter(String topicAndFilter) {
//
// }
public String getTopic() {
return topic;
}
public Map<String,String> getFilter() {
return filter;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((topic == null) ? 0 : topic.hashCode());
result = prime * result + ((filter == null) ? 0 : filter.hashCode());
return result;
}
// public int hashCode() {
// if(right!=null){
// return (left.toString()+right.toString()).hashCode();
// }else return left.toString().hashCode();
// }
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof TopicAndFilter))
return false;
TopicAndFilter other = (TopicAndFilter) obj;
if (topic == null) {
if (other.topic != null)
return false;
} else if (!topic.equals(other.topic))
return false;
if (filter == null) {
if (other.filter != null)
return false;
} else if (!filter.equals(other.filter))
return false;
return true;
}
@Override
public String toString() {
if(filter!=null)
return topic + filter.toString() ;
else return topic +"null";
}
}

View File

@@ -0,0 +1,94 @@
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package com.alibaba.middleware.race.mom.util;
public class Triple<L, M, R> {
private final L left;
private final M middle;
private final R right;
public Triple(L left, M middle, R right) {
if (left == null) {
throw new IllegalArgumentException("Left value is not effective.");
}
if (middle == null) {
throw new IllegalArgumentException("Middle value is not effective.");
}
if (right == null) {
throw new IllegalArgumentException("Right value is not effective.");
}
this.left = left;
this.middle = middle;
this.right = right;
}
public L getLeft() {
return this.left;
}
public M getMiddle() {
return this.middle;
}
public R getRight() {
return this.right;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((left == null) ? 0 : left.hashCode());
result = prime * result + ((middle == null) ? 0 : middle.hashCode());
result = prime * result + ((right == null) ? 0 : right.hashCode());
return result;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Triple<Object, Object, Object> other = (Triple<Object, Object, Object>) obj;
if (left == null) {
if (other.left != null)
return false;
} else if (!left.equals(other.left))
return false;
if (middle == null) {
if (other.middle != null)
return false;
} else if (!middle.equals(other.middle))
return false;
if (right == null) {
if (other.right != null)
return false;
} else if (!right.equals(other.right))
return false;
return true;
}
@Override
public String toString() {
return "<" + left + "," + middle + "," + right + ">";
}
}

View File

@@ -0,0 +1,93 @@
log4j.rootCategory=error,stdout
log4j.addivity.org.apache=true
#stout 控制台打印
log4j.appender.stdout.Encoding=UTF-8
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#log4j.appender.stdout.layout.ConversionPattern=[QC] %-d{yyyy-MM-dd HH:mm:ss} %p [%t] %C.%M(%L) | %m%n
log4j.appender.stdout.layout.ConversionPattern= %p %C.%M(%L) | %m%n
#自定义打印到文件
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=mom.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
## Disable other log 不打印的包日记
log4j.logger.io.netty=OFF
log4j.logger.org.springframework=OFF
log4j.logger.org.apache.struts2=OFF
log4j.logger.com.opensymphony.xwork2=OFF
log4j.logger.com.ibatis=OFF
log4j.logger.org.hibernate=OFF
#暂时没有使用下面的logger
# 应用于控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=GBK
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# 每天新建日志
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=C\:/log4j/log
log4j.appender.A1.Encoding=GBK
log4j.appender.A1.Threshold=DEBUG
log4j.appender.A1.DatePattern='.'yyyy-MM-dd
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}\:%L \: %m%n
#应用于文件
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=C\:/log4j/file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.Encoding=GBK
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# 应用于文件回滚
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.CONSOLE_FILE.Encoding=GBK
log4j.appender.ROLLING_FILE.MaxFileSize=10KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=1
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#自定义Appender
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = yyflyons@163.com
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#应用于socket
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n
# Log Factor 5 Appender
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
# 发送日志给邮件
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=yyflyons@163.com
log4j.appender.MAIL.SMTPHost=www.wusetu.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=yyflyons@126.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

View File

@@ -0,0 +1,40 @@
package com.alibaba.middleware.race.mom;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest {
private static ExecutorService executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public static void main(String args[]) throws InterruptedException{
long start=System.currentTimeMillis();
for (int i = 0; i <Runtime.getRuntime().availableProcessors(); i++) {
executorService.execute(new Runnable() {
int i=0;
@Override
public void run() {
while (true) {
try {
System.out.println(i++);
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
Thread.sleep(3000);
if (true) {
System.out.println("over");
return ;
}
}
}

View File

@@ -0,0 +1,104 @@
package com.alibaba.middleware.race.mom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
class Group {
long id;
String name;
HashMap<String, String> properties = new HashMap<String, String>();
public String getProperty(String key) {
return properties.get(key);
}
/**
* 设置消息属性
* @param key
* @param value
*/
public void setProperty(String key, String value) {
properties.put(key, value);
}
/**
* 删除消息属性
* @param key
*/
public void removeProperty(String key) {
properties.remove(key);
}
public Map<String, String> getProperties() {
return properties;
}
List<User> user = new ArrayList<User>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<User> getUser() {
return user;
}
public void setUser(List<User> user) {
this.user = user;
}
}
class User {
long id;
String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class fstjson {
public static void main(String[] args) {
Group group = new Group();
group.setId(0L);
group.setName("admin");
group.setProperty("1", "1");
User guestUser = new User();
guestUser.setId(2L);
guestUser.setName("guest");
User rootUser = new User();
rootUser.setId(3L);
rootUser.setName("root");
group.getUser().add(guestUser);
group.getUser().add(rootUser);
String jsonString = JSON.toJSONString(group);
System.out.println(jsonString);
}
}

View File

@@ -0,0 +1,47 @@
package com.alibaba.middleware.race.mom;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class test extends Thread{
public static BlockingQueue<String> queue=new LinkedBlockingQueue<String>(3);
private int index;
public test(int i){
this.index=i;
}
public void run(){
try{
queue.put(String.valueOf(this.index));
System.out.println("put {"+this.index+"} into queue!");
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String args[]){
ExecutorService service=Executors.newCachedThreadPool();
for( int i=0; i<10; i++){
service.submit(new test(i));
}
Thread thread = new Thread(){
public void run(){
try{
while(true){
Thread.sleep((int)(Math.random()*1000));
// if(test.queue.isEmpty()) break;
String str=test.queue.take();
System.out.println("take {" + str+"} out of queue!");
}
}catch(Exception e){
e.printStackTrace();
}
}
};
service.submit(thread);
service.shutdown();
}
}

View File

@@ -0,0 +1,30 @@
<assembly>
<id>bin</id>
<baseDirectory>middleware-mom</baseDirectory>
<includeBaseDirectory>true</includeBaseDirectory>
<formats>
<format>dir</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>README*</include>
<include>LICENSE*</include>
<include>NOTICE*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/lib</directory>
<outputDirectory>lib</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>

Some files were not shown because too many files have changed in this diff Show More