PageRenderTime 63ms CodeModel.GetById 35ms RepoModel.GetById 0ms app.codeStats 0ms

/casbah-core/src/main/scala/util/OpLog.scala

https://github.com/JanxSpirit/casbah
Scala | 142 lines | 86 code | 28 blank | 28 comment | 0 complexity | 8be386f9b518a00091b3fa4c4f40f730 MD5 | raw file
  1. /**
  2. * Copyright (c) 2010, 2011 10gen, Inc. <http://10gen.com>
  3. * Copyright (c) 2009, 2010 Novus Partners, Inc. <http://novus.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * For questions and comments about this product, please see the project page at:
  18. *
  19. * http://github.com/mongodb/casbah
  20. *
  21. */
  22. package com.mongodb.casbah
  23. package util
  24. import org.bson.types.BSONTimestamp
  25. import com.mongodb.Bytes
  26. import scala.util.control.Exception._
  27. class MongoOpLog(mongo: MongoConnection = MongoConnection(),
  28. startTimestamp: Option[BSONTimestamp] = None,
  29. namespace: Option[String] = None) extends Iterator[MongoOpLogEntry] with Logging {
  30. implicit object BSONTimestampOk extends ValidDateOrNumericType[org.bson.types.BSONTimestamp]
  31. protected val local = mongo("local")
  32. protected val oplog = local("oplog.$main")
  33. val tsp = verifyOpLog
  34. log.debug("Beginning monitoring OpLog at '%s'", tsp)
  35. val q = namespace match {
  36. case Some(ns) => ("ts" $gt tsp) ++ ("ns" -> ns)
  37. case None => "ts" $gt tsp
  38. }
  39. log.debug("OpLog Filter: '%s'", q)
  40. val cursor = oplog.find(q)
  41. cursor.options = Bytes.QUERYOPTION_TAILABLE
  42. cursor.options = Bytes.QUERYOPTION_AWAITDATA
  43. def hasNext = cursor.hasNext
  44. def next = MongoOpLogEntry(cursor.next)
  45. def verifyOpLog: BSONTimestamp = {
  46. // Verify the oplog exists
  47. val last = oplog.find().sort(MongoDBObject("$natural" -> 1)).limit(1)
  48. assume(last.hasNext,
  49. "No oplog found. mongod must be a --master or belong to a Replica Set.")
  50. /**
  51. * If a startTimestamp was specified attempt to sync from there.
  52. * An exception is thrown if the timestamp isn't found because
  53. * you won't be able to sync.
  54. */
  55. startTimestamp match {
  56. case Some(ts) => {
  57. oplog.findOne(MongoDBObject("ts" -> ts)).orElse(
  58. throw new Exception("No oplog entry for requested start timestamp."))
  59. ts
  60. }
  61. case None => last.next().as[BSONTimestamp]("ts")
  62. }
  63. }
  64. }
  65. object MongoOpLogEntry {
  66. def apply(entry: MongoDBObject) = entry("op") match {
  67. case InsertOp =>
  68. MongoInsertOperation(
  69. entry.as[BSONTimestamp]("ts"),
  70. entry.as[Long]("h"),
  71. entry.as[String]("ns"),
  72. entry.as[DBObject]("o"))
  73. case UpdateOp =>
  74. MongoUpdateOperation(
  75. entry.as[BSONTimestamp]("ts"),
  76. entry.as[Long]("h"),
  77. entry.as[String]("ns"),
  78. entry.as[DBObject]("o"),
  79. entry.as[DBObject]("o2"))
  80. case DeleteOp =>
  81. MongoInsertOperation(
  82. entry.as[BSONTimestamp]("ts"),
  83. entry.as[Long]("h"),
  84. entry.as[String]("ns"),
  85. entry.as[DBObject]("o"))
  86. }
  87. }
  88. sealed trait MongoOpType { def typeCode: String }
  89. case object InsertOp extends MongoOpType { val typeCode = "i" }
  90. case object UpdateOp extends MongoOpType { val typeCode = "u" }
  91. case object DeleteOp extends MongoOpType { val typeCode = "d" }
  92. sealed trait MongoOpLogEntry {
  93. val timestamp: BSONTimestamp
  94. lazy val ts = timestamp
  95. val opID: Long
  96. lazy val h = opID
  97. val opType: MongoOpType
  98. lazy val op = opType
  99. val namespace: String
  100. lazy val ns = namespace
  101. val document: MongoDBObject
  102. lazy val o = document
  103. }
  104. case class MongoInsertOperation(timestamp: BSONTimestamp, opID: Long, namespace: String, document: MongoDBObject) extends MongoOpLogEntry {
  105. val opType = InsertOp
  106. }
  107. case class MongoUpdateOperation(timestamp: BSONTimestamp, opID: Long, namespace: String, document: MongoDBObject, documentID: MongoDBObject) extends MongoOpLogEntry {
  108. val opType = UpdateOp
  109. lazy val o2 = documentID
  110. }
  111. case class MongoDeleteOperation(timestamp: BSONTimestamp, opID: Long, namespace: String, document: MongoDBObject) extends MongoOpLogEntry {
  112. val opType = DeleteOp
  113. }
  114. // vim: set ts=2 sw=2 sts=2 et: