PageRenderTime 109ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/ParaBond/src/scaly/parabond/util/MongoHelper.scala

http://scaly.googlecode.com/
Scala | 292 lines | 143 code | 70 blank | 79 comment | 4 complexity | 1f1f555f344fae14b491adc0e95090f0 MD5 | raw file
  1. /*
  2. * Copyright (c) Scaly Contributors
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the Scaly Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. package scaly.parabond.util
  28. import com.mongodb.casbah.MongoCursor
  29. import scaly.parabond.entry.SimpleBond
  30. import com.mongodb.BasicDBObject
  31. import com.mongodb.BasicDBList
  32. import scala.collection.JavaConverters._
  33. import scala.util.Random
  34. import com.mongodb.casbah.MongoConnection
  35. import com.mongodb.casbah.commons.MongoDBObject
  36. import scala.actors._
  37. import Actor._
  38. import com.mongodb.casbah.MongoCollection
  39. /** Converts mongo cursor to a simple bond */
  40. object MongoHelper {
  41. /** Sets the mongo host */
  42. val host: String = getHost
  43. /** Connects to the parabond DB */
  44. // val mongo = MongoConnection("127.0.0.1")("parabond")
  45. val mongo = MongoConnection(host)("parabond")
  46. /** Initialize the random number generator */
  47. val ran = new Random(0)
  48. case class Intermediate(portfId: Int, list : List[SimpleBond])
  49. case class Intermediate2(bonds: List[SimpleBond])
  50. /**
  51. * Loads a list of 2-tuples of portfolios x list of bonds
  52. */
  53. def loadPortfs(n : Int) : List[(Int,List[SimpleBond])] = {
  54. // Connect to the portfolio collection
  55. val portfsCollecton = mongo("Portfolios")
  56. val input = (1 to n).foldLeft(List[(Int,List[SimpleBond])] ()) { (list, pid) =>
  57. // Select a portfolio
  58. val lottery = ran.nextInt(100000) + 1
  59. // Retrieve the portfolio
  60. val portfsQuery = MongoDBObject("id" -> lottery)
  61. val portfsCursor = portfsCollecton.find(portfsQuery)
  62. // Get the bonds in the portfolio
  63. val bondIds = MongoHelper.asList(portfsCursor, "instruments")
  64. // Connect to the bonds collection
  65. val bondsCollection = mongo("Bonds")
  66. val bonds = bondIds.foldLeft(List[SimpleBond]()) { (bonds, id) =>
  67. // Get the bond from the bond collection
  68. val bondQuery = MongoDBObject("id" -> id)
  69. val bondCursor: MongoCursor = bondsCollection.find(bondQuery)
  70. val bond = MongoHelper.asBond(bondCursor)
  71. // The price into the aggregate sum
  72. bonds ++ List(bond)
  73. }
  74. list ++ List((lottery,bonds))
  75. }
  76. input
  77. }
  78. /**
  79. * Parallel load the portfolios and bonds into memory (actor-based).
  80. */
  81. def loadPortfsParallel(n : Int) : List[(Int,List[SimpleBond])] = {
  82. val portfsCollection = mongo("Portfolios")
  83. val caller = self
  84. (1 to n).foreach { p =>
  85. // Select a portfolio
  86. val lottery = ran.nextInt(100000) + 1
  87. actor {
  88. caller ! fetchBonds(lottery, portfsCollection)
  89. }
  90. }
  91. var list = List[(Int, List[SimpleBond])]()
  92. (1 to n).foreach { p =>
  93. receive {
  94. case Intermediate(portfId, bonds) =>
  95. list = list ++ List((portfId, bonds))
  96. }
  97. }
  98. list
  99. }
  100. /**
  101. * Loads portfolios x bonds into memory
  102. */
  103. def loadPortfsPar(n: Int): List[(Int,List[SimpleBond])] = {
  104. val portfsCollection = mongo("Portfolios")
  105. val lotteries = for(i <- 0 to n) yield ran.nextInt(100000)+1
  106. val list = lotteries.par.foldLeft (List[(Int,List[SimpleBond])]())
  107. { (portfIdBonds,portfId) =>
  108. val intermediate = fetchBonds(portfId,portfsCollection)
  109. (portfId,intermediate.list) :: portfIdBonds
  110. }
  111. list
  112. }
  113. /**
  114. * Fetch the bonds from the database.
  115. */
  116. def fetchBonds(portfId: Int,portfsCollection: MongoCollection): Intermediate = {
  117. // Retrieve the portfolio
  118. val portfsQuery = MongoDBObject("id" -> portfId)
  119. val portfsCursor = portfsCollection.find(portfsQuery)
  120. // Get the bonds in the portfolio
  121. val bondIds = MongoHelper.asList(portfsCursor, "instruments")
  122. // Connect to the bonds collection
  123. val bondsCollection = mongo("Bonds")
  124. val bonds = bondIds.foldLeft(List[SimpleBond]()) { (bonds, id) =>
  125. // Get the bond from the bond collection
  126. val bondQuery = MongoDBObject("id" -> id)
  127. val bondCursor: MongoCursor = bondsCollection.find(bondQuery)
  128. val bond = MongoHelper.asBond(bondCursor)
  129. // The price into the aggregate sum
  130. bonds ++ List(bond)
  131. }
  132. // Method below runs out of semaphores on mongo
  133. // val bonds = fetchBondsParallel(bondIds,bondsCollection)
  134. Intermediate(portfId,bonds)
  135. }
  136. /**
  137. * Fetches bonds in parallel from the database
  138. */
  139. def fetchBondsParallel(bondIds : List[Int], bondsColledtion : MongoCollection) : List[SimpleBond] = {
  140. val caller = self
  141. bondIds.foreach { id =>
  142. actor {
  143. val bondQuery = MongoDBObject("id" -> id)
  144. val bondCursor: MongoCursor = bondsColledtion.find(bondQuery)
  145. val bond = MongoHelper.asBond(bondCursor)
  146. println("got "+id)
  147. caller ! bond
  148. }
  149. }
  150. var bonds = List[SimpleBond]( )
  151. (1 to bondIds.size).foreach { p =>
  152. receive {
  153. case bond : SimpleBond =>
  154. bonds = bonds ++ List(bond)
  155. }
  156. }
  157. bonds
  158. }
  159. /**
  160. * Converts the mongo cursor to a bond -- assuming the query cursor
  161. * as a single bond
  162. */
  163. def asBond(cursor: MongoCursor) : SimpleBond = {
  164. val cur = cursor.map { p =>
  165. p match {
  166. case b : BasicDBObject =>
  167. val id = b.get("id").toString.toInt
  168. val coupon = b.get("coupon").toString.toDouble
  169. val freq = b.get("freq").toString.toInt
  170. val tenor = b.get("tenor").toString.toDouble
  171. val maturity = b.get("maturity").toString.toDouble
  172. new SimpleBond(id,coupon,freq,tenor,maturity)
  173. }
  174. }
  175. cur.next
  176. }
  177. /** Converts mongo cursor to scala list of int objects */
  178. def asList(cursor: MongoCursor,field : String) : List[Int] = {
  179. val cur = cursor.map { p =>
  180. // Get mongo ids which is a BasicDBList -- but Scala
  181. // can't handle this with FP so we need to convert it
  182. // an immutable list that FP can handle
  183. val ids = p.get(field)
  184. ids match {
  185. case listAsJava : BasicDBList =>
  186. val listInteger = listAsJava.asScala
  187. val list = listInteger.map { p =>
  188. p match {
  189. case intAsJava : java.lang.Integer =>
  190. intAsJava.toInt
  191. }
  192. }
  193. list.toList
  194. case _ =>
  195. null
  196. }
  197. }
  198. // cur is an Iterator[List[Int]] of size 1
  199. cur.next
  200. }
  201. /**
  202. * Updates the price of a portfolio with the price.
  203. */
  204. def updatePrice(portfId: Int, price: Double) {
  205. // Retrive the portfolio
  206. val portfsCollecton = mongo("Portfolios")
  207. val portfsQuery = MongoDBObject("id" -> portfId)
  208. val portfsCursor : MongoCursor = portfsCollecton.find(portfsQuery)
  209. val portf = portfsCursor.next
  210. // Set the price
  211. portf.put("price", price)
  212. // Write-back the portfolio
  213. mongo("Portfolios").save(portf)
  214. }
  215. /**
  216. * Gets the mongo host
  217. * */
  218. def getHost : String = {
  219. val host = System.getProperty("host")
  220. if(host != null) host else "127.0.0.1"
  221. }
  222. }