PageRenderTime 82ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/rocketmq-client/src/main/java/com/alibaba/rocketmq/client/consumer/store/LocalFileOffsetStore.java

https://gitlab.com/xialeizhou/RocketMQ
Java | 226 lines | 172 code | 33 blank | 21 comment | 45 complexity | 5d2d21cff9a208b27031ba619d47f11f MD5 | raw file
  1. /**
  2. * Copyright (C) 2010-2013 Alibaba Group Holding Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.alibaba.rocketmq.client.consumer.store;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.util.HashMap;
  20. import java.util.Iterator;
  21. import java.util.Map;
  22. import java.util.Set;
  23. import java.util.concurrent.ConcurrentHashMap;
  24. import java.util.concurrent.atomic.AtomicLong;
  25. import org.slf4j.Logger;
  26. import com.alibaba.rocketmq.client.exception.MQClientException;
  27. import com.alibaba.rocketmq.client.impl.factory.MQClientInstance;
  28. import com.alibaba.rocketmq.client.log.ClientLogger;
  29. import com.alibaba.rocketmq.common.MixAll;
  30. import com.alibaba.rocketmq.common.UtilAll;
  31. import com.alibaba.rocketmq.common.help.FAQUrl;
  32. import com.alibaba.rocketmq.common.message.MessageQueue;
  33. /**
  34. * Local storage implementation
  35. *
  36. * @author shijia.wxr<vintage.wang@gmail.com>
  37. * @since 2013-7-24
  38. */
  39. public class LocalFileOffsetStore implements OffsetStore {
  40. public final static String LocalOffsetStoreDir = System.getProperty(
  41. "rocketmq.client.localOffsetStoreDir",
  42. System.getProperty("user.home") + File.separator + ".rocketmq_offsets");
  43. private final static Logger log = ClientLogger.getLog();
  44. private final MQClientInstance mQClientFactory;
  45. private final String groupName;
  46. private final String storePath;
  47. private ConcurrentHashMap<MessageQueue, AtomicLong> offsetTable =
  48. new ConcurrentHashMap<MessageQueue, AtomicLong>();
  49. public LocalFileOffsetStore(MQClientInstance mQClientFactory, String groupName) {
  50. this.mQClientFactory = mQClientFactory;
  51. this.groupName = groupName;
  52. this.storePath = LocalOffsetStoreDir + File.separator + //
  53. this.mQClientFactory.getClientId() + File.separator + //
  54. this.groupName + File.separator + //
  55. "offsets.json";
  56. }
  57. @Override
  58. public void load() throws MQClientException {
  59. OffsetSerializeWrapper offsetSerializeWrapper = this.readLocalOffset();
  60. if (offsetSerializeWrapper != null && offsetSerializeWrapper.getOffsetTable() != null) {
  61. offsetTable.putAll(offsetSerializeWrapper.getOffsetTable());
  62. for (MessageQueue mq : offsetSerializeWrapper.getOffsetTable().keySet()) {
  63. AtomicLong offset = offsetSerializeWrapper.getOffsetTable().get(mq);
  64. log.info("load consumer's offset, {} {} {}",//
  65. this.groupName,//
  66. mq,//
  67. offset.get());
  68. }
  69. }
  70. }
  71. @Override
  72. public void updateOffset(MessageQueue mq, long offset, boolean increaseOnly) {
  73. if (mq != null) {
  74. AtomicLong offsetOld = this.offsetTable.get(mq);
  75. if (null == offsetOld) {
  76. offsetOld = this.offsetTable.putIfAbsent(mq, new AtomicLong(offset));
  77. }
  78. if (null != offsetOld) {
  79. if (increaseOnly) {
  80. MixAll.compareAndIncreaseOnly(offsetOld, offset);
  81. } else {
  82. offsetOld.set(offset);
  83. }
  84. }
  85. }
  86. }
  87. @Override
  88. public long readOffset(final MessageQueue mq, final ReadOffsetType type) {
  89. if (mq != null) {
  90. switch (type) {
  91. case MEMORY_FIRST_THEN_STORE:
  92. case READ_FROM_MEMORY: {
  93. AtomicLong offset = this.offsetTable.get(mq);
  94. if (offset != null) {
  95. return offset.get();
  96. } else if (ReadOffsetType.READ_FROM_MEMORY == type) {
  97. return -1;
  98. }
  99. }
  100. case READ_FROM_STORE: {
  101. OffsetSerializeWrapper offsetSerializeWrapper;
  102. try {
  103. offsetSerializeWrapper = this.readLocalOffset();
  104. } catch (MQClientException e) {
  105. return -1;
  106. }
  107. if (offsetSerializeWrapper != null && offsetSerializeWrapper.getOffsetTable() != null) {
  108. AtomicLong offset = offsetSerializeWrapper.getOffsetTable().get(mq);
  109. if (offset != null) {
  110. this.updateOffset(mq, offset.get(), false);
  111. return offset.get();
  112. }
  113. }
  114. }
  115. default:
  116. break;
  117. }
  118. }
  119. return -1;
  120. }
  121. @Override
  122. public void persistAll(Set<MessageQueue> mqs) {
  123. if (null == mqs || mqs.isEmpty())
  124. return;
  125. OffsetSerializeWrapper offsetSerializeWrapper = new OffsetSerializeWrapper();
  126. for (MessageQueue mq : this.offsetTable.keySet()) {
  127. if (mqs.contains(mq)) {
  128. AtomicLong offset = this.offsetTable.get(mq);
  129. offsetSerializeWrapper.getOffsetTable().put(mq, offset);
  130. }
  131. }
  132. String jsonString = offsetSerializeWrapper.toJson(true);
  133. if (jsonString != null) {
  134. try {
  135. MixAll.string2File(jsonString, this.storePath);
  136. } catch (IOException e) {
  137. log.error("persistAll consumer offset Exception, " + this.storePath, e);
  138. }
  139. }
  140. }
  141. @Override
  142. public void persist(MessageQueue mq) {
  143. }
  144. private OffsetSerializeWrapper readLocalOffset() throws MQClientException {
  145. String content = MixAll.file2String(this.storePath);
  146. if (null == content || content.length() == 0) {
  147. return this.readLocalOffsetBak();
  148. } else {
  149. OffsetSerializeWrapper offsetSerializeWrapper = null;
  150. try {
  151. offsetSerializeWrapper =
  152. OffsetSerializeWrapper.fromJson(content, OffsetSerializeWrapper.class);
  153. } catch (Exception e) {
  154. log.warn("readLocalOffset Exception, and try to correct", e);
  155. return this.readLocalOffsetBak();
  156. }
  157. return offsetSerializeWrapper;
  158. }
  159. }
  160. private OffsetSerializeWrapper readLocalOffsetBak() throws MQClientException {
  161. String content = MixAll.file2String(this.storePath + ".bak");
  162. if (content != null && content.length() > 0) {
  163. OffsetSerializeWrapper offsetSerializeWrapper = null;
  164. try {
  165. offsetSerializeWrapper =
  166. OffsetSerializeWrapper.fromJson(content, OffsetSerializeWrapper.class);
  167. } catch (Exception e) {
  168. log.warn("readLocalOffset Exception", e);
  169. throw new MQClientException("readLocalOffset Exception, maybe fastjson version too low" //
  170. + FAQUrl.suggestTodo(FAQUrl.LOAD_JSON_EXCEPTION), //
  171. e);
  172. }
  173. return offsetSerializeWrapper;
  174. }
  175. return null;
  176. }
  177. @Override
  178. public void removeOffset(MessageQueue mq) {
  179. }
  180. @Override
  181. public Map<MessageQueue, Long> cloneOffsetTable(String topic) {
  182. Map<MessageQueue, Long> cloneOffsetTable = new HashMap<MessageQueue, Long>();
  183. Iterator<MessageQueue> iterator = this.offsetTable.keySet().iterator();
  184. while (iterator.hasNext()) {
  185. MessageQueue mq = iterator.next();
  186. if (!UtilAll.isBlank(topic) && !topic.equals(mq.getTopic())) {
  187. continue;
  188. }
  189. cloneOffsetTable.put(mq, this.offsetTable.get(mq).get());
  190. }
  191. return cloneOffsetTable;
  192. }
  193. }