├── .gitignore
├── README.md
├── hakuku-master
├── .cache
├── conf
│ ├── users.conf
│ └── servants.conf
├── src
│ └── hakuku
│ │ └── master
│ │ ├── Constants.scala
│ │ ├── Master.scala
│ │ ├── Memory.scala
│ │ └── MasterRequest.scala
├── .classpath
├── .project
└── .settings
│ └── org.eclipse.jdt.core.prefs
├── hakuku-servant
├── .cache
├── src
│ └── hakuku
│ │ └── servant
│ │ ├── Constants.scala
│ │ ├── Servant.scala
│ │ ├── ServantRequest.scala
│ │ └── Memory.scala
├── .classpath
├── .project
└── .settings
│ ├── org.eclipse.jdt.core.prefs
│ └── org.scala-ide.sdt.core.prefs
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.class
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | hakuku
2 | ======
3 |
4 | in-memory high performance distributed caching
5 |
--------------------------------------------------------------------------------
/hakuku-master/.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngsankha/hakuku/master/hakuku-master/.cache
--------------------------------------------------------------------------------
/hakuku-servant/.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ngsankha/hakuku/master/hakuku-servant/.cache
--------------------------------------------------------------------------------
/hakuku-master/conf/users.conf:
--------------------------------------------------------------------------------
1 | # Users authentication file
2 | # Add the details of authentication in the form username=password
3 |
4 | test=abc123
--------------------------------------------------------------------------------
/hakuku-master/conf/servants.conf:
--------------------------------------------------------------------------------
1 | # This file is the list of IP Addresses of the servants
2 | # Put the IP Address of each servant in a newline
3 | 127.0.0.1
--------------------------------------------------------------------------------
/hakuku-servant/src/hakuku/servant/Constants.scala:
--------------------------------------------------------------------------------
1 | package hakuku.servant
2 |
3 | object Constants {
4 |
5 | val PORT = 2001
6 | val MIN_MEM: Long = 1024*1024*1024*1024
7 |
8 | }
--------------------------------------------------------------------------------
/hakuku-master/src/hakuku/master/Constants.scala:
--------------------------------------------------------------------------------
1 | package hakuku.master
2 |
3 | import java.util.Properties
4 |
5 | object Constants {
6 |
7 | val PORT = 2002
8 | val SERVANT_PORT = 2001
9 | var users = new Properties
10 | }
--------------------------------------------------------------------------------
/hakuku-master/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/hakuku-servant/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/hakuku-servant/src/hakuku/servant/Servant.scala:
--------------------------------------------------------------------------------
1 | package hakuku.servant
2 |
3 | import java.net.ServerSocket
4 | import scala.concurrent.ops._
5 |
6 | object Servant {
7 | var r = Runtime getRuntime
8 |
9 | def main(args: Array[String]) {
10 | val server = new ServerSocket(Constants PORT)
11 | println("Hakuku Servant up and running...")
12 | while(true) {
13 | val socket = server accept
14 | var request = new ServantRequest(socket)
15 | spawn { request loop}
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/hakuku-master/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | hakuku-master
4 |
5 |
6 |
7 |
8 |
9 | org.scala-ide.sdt.core.scalabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.scala-ide.sdt.core.scalanature
16 | org.eclipse.jdt.core.javanature
17 |
18 |
19 |
--------------------------------------------------------------------------------
/hakuku-servant/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | hakuku-servant
4 |
5 |
6 |
7 |
8 |
9 | org.scala-ide.sdt.core.scalabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.scala-ide.sdt.core.scalanature
16 | org.eclipse.jdt.core.javanature
17 |
18 |
19 |
--------------------------------------------------------------------------------
/hakuku-master/src/hakuku/master/Master.scala:
--------------------------------------------------------------------------------
1 | package hakuku.master
2 |
3 | import java.net.ServerSocket
4 | import java.io.FileInputStream
5 | import scala.concurrent.ops._
6 |
7 | object Master {
8 |
9 | def main(args: Array[String]) {
10 | val server = new ServerSocket(Constants PORT)
11 | Constants.users.load(new FileInputStream("conf/users.conf"))
12 | println("Connecting to the servants...")
13 | Memory.loadIpMem
14 | println("Hakuku Master Server up and running...")
15 | while(true) {
16 | val socket = server accept
17 | var request = new MasterRequest(socket)
18 | spawn { request loop}
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/hakuku-master/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Fri May 25 13:10:36 IST 2012
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
6 | org.eclipse.jdt.core.compiler.compliance=1.6
7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
12 | org.eclipse.jdt.core.compiler.source=1.6
13 |
--------------------------------------------------------------------------------
/hakuku-servant/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Tue May 22 20:37:59 IST 2012
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
6 | org.eclipse.jdt.core.compiler.compliance=1.6
7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
12 | org.eclipse.jdt.core.compiler.source=1.6
13 |
--------------------------------------------------------------------------------
/hakuku-servant/src/hakuku/servant/ServantRequest.scala:
--------------------------------------------------------------------------------
1 | package hakuku.servant
2 |
3 | import java.net.Socket
4 | import java.io.InputStreamReader
5 | import java.io.BufferedReader
6 | import java.io.PrintWriter
7 | import java.util.StringTokenizer
8 |
9 | class ServantRequest(socket: Socket) {
10 |
11 | var in = new BufferedReader(new InputStreamReader(socket getInputStream))
12 | var out = new PrintWriter(socket getOutputStream,true)
13 |
14 | def loop {
15 | out println("HELLO")
16 | while(socket isConnected) {
17 | var st = new StringTokenizer(in readLine)
18 | var res: String = null
19 | val cmd = st nextToken()
20 | if(cmd == "ADD")
21 | out println(Memory.add(st nextToken, st nextToken))
22 | else if(cmd == "GET")
23 | out println(Memory.get(st nextToken))
24 | else if(cmd == "MEMQUERY")
25 | out println(Servant.r.freeMemory)
26 | else
27 | out println("ERROR")
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Sankha Narayan Guria
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/hakuku-master/src/hakuku/master/Memory.scala:
--------------------------------------------------------------------------------
1 | package hakuku.master
2 |
3 | import scala.collection.mutable.HashMap
4 | import java.util.TreeMap
5 | import java.util.NoSuchElementException
6 | import java.io.BufferedReader
7 | import java.io.InputStreamReader
8 | import java.io.FileInputStream
9 | import java.net.Socket
10 | import java.io.PrintWriter
11 |
12 | object Memory {
13 |
14 | var iptable = new HashMap[String, Socket]
15 | var ipMem = new HashMap[Socket, Long]
16 | var memIp = new TreeMap[Long, Socket]
17 |
18 | def loadIpMem {
19 | var reader = new BufferedReader(new InputStreamReader(new FileInputStream("conf/servants.conf")))
20 | var line = reader.readLine
21 | while(line != null) {
22 | if(!line.startsWith("#")) {
23 | val s = new Socket(line, Constants.SERVANT_PORT)
24 | val in = new BufferedReader(new InputStreamReader(s getInputStream))
25 | val out = new PrintWriter(s getOutputStream, true)
26 | if(in.readLine == "HELLO") {
27 | out println("MEMQUERY")
28 | val mem: Long = java.lang.Long parseLong(in readLine)
29 | ipMem += (s -> mem)
30 | memIp.put(mem, s)
31 | }
32 | }
33 | line = reader.readLine
34 | }
35 | println(ipMem)
36 | }
37 | }
--------------------------------------------------------------------------------
/hakuku-servant/src/hakuku/servant/Memory.scala:
--------------------------------------------------------------------------------
1 | package hakuku.servant
2 |
3 | import scala.collection.mutable.HashMap
4 | import java.util.TreeMap
5 | import java.util.NoSuchElementException
6 |
7 | object Memory {
8 |
9 | var mem = new HashMap[String, String]
10 | var keyTime = new HashMap[String, Long]
11 | var timeKey = new TreeMap[Long, String]
12 |
13 | def add(key: String, value: String): String = synchronized {
14 | if(Servant.r.freeMemory < Constants.MIN_MEM) {
15 | val key = timeKey.get(timeKey.lastKey)
16 | mem -= key
17 | keyTime -= key
18 | timeKey.remove(timeKey.lastKey())
19 | System gc
20 | }
21 | val time = System.currentTimeMillis
22 | mem += (key -> value)
23 | try {
24 | val oldTime = keyTime(key)
25 | timeKey.remove(oldTime)
26 | } catch {
27 | case _: NoSuchElementException =>
28 | }
29 | keyTime += (key -> time)
30 | timeKey.put(time, key)
31 | println("Added key " + key)
32 | "OK " + Servant.r.freeMemory()
33 | }
34 |
35 | def get(key: String): String = synchronized {
36 | var res: String = null
37 | try{
38 | res = "OK " + mem(key)
39 | val oldTime = keyTime(key)
40 | timeKey.remove(oldTime)
41 | val time = System.currentTimeMillis
42 | keyTime += (key -> time)
43 | timeKey.put(time, key)
44 | } catch {
45 | case _: NoSuchElementException => res = "ERROR"
46 | }
47 | res
48 | }
49 | }
--------------------------------------------------------------------------------
/hakuku-master/src/hakuku/master/MasterRequest.scala:
--------------------------------------------------------------------------------
1 | package hakuku.master
2 |
3 | import java.net.Socket
4 | import java.io.BufferedReader
5 | import java.io.InputStreamReader
6 | import java.io.PrintWriter
7 | import java.util.StringTokenizer
8 |
9 | class MasterRequest(socket: Socket) {
10 |
11 | var in = new BufferedReader(new InputStreamReader(socket getInputStream))
12 | var out = new PrintWriter(socket getOutputStream,true)
13 | var servantIn: BufferedReader = null
14 | var servantOut: PrintWriter = null
15 | var authed = false
16 | var reply = ""
17 |
18 | def loop {
19 | out println("HELLO")
20 | while(socket isConnected) {
21 | var st = new StringTokenizer(in readLine)
22 | var res: String = null
23 | val cmd = st nextToken()
24 | if(cmd == "LOGIN")
25 | out println(auth(st nextToken, st nextToken))
26 | else if(cmd == "ADD" && authed)
27 | out println(add(st nextToken, st nextToken))
28 | else if(cmd == "GET" && authed)
29 | out println(get(st nextToken))
30 | else
31 | out println("ERROR")
32 | }
33 | }
34 |
35 | def auth(username: String, password: String): String = {
36 | if(Constants.users.getProperty(username) == password) authed = true
37 | println("Login from "+username)
38 | if(authed) "OK" else "ERROR"
39 | }
40 |
41 | def add(key: String, value: String): String = {
42 | if(Memory.iptable.contains(key)) Memory.iptable -= key
43 | val s = Memory.memIp.get(Memory.memIp.lastKey)
44 | servantIn = new BufferedReader(new InputStreamReader(s getInputStream))
45 | servantOut = new PrintWriter(s getOutputStream,true)
46 | servantOut println("ADD " + key + " " + value)
47 | reply = servantIn readLine
48 | val mem = java.lang.Long.parseLong(reply.substring(reply.lastIndexOf(' ') + 1))
49 | Memory.memIp.remove(Memory.memIp.lastKey)
50 | Memory.ipMem += (s -> mem)
51 | Memory.memIp.put(mem, s)
52 | Memory.iptable += (key -> s)
53 | "OK"
54 | }
55 |
56 | def get(key: String): String = {
57 | if(!Memory.iptable.contains(key)) "ERROR"
58 | else {
59 | val s = Memory.iptable(key)
60 | servantIn = new BufferedReader(new InputStreamReader(s getInputStream))
61 | servantOut = new PrintWriter(s getOutputStream,true)
62 | servantOut println("GET " + key)
63 | servantIn readLine
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/hakuku-servant/.settings/org.scala-ide.sdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | formatter.alignParameters=false
3 | formatter.alignSingleLineCaseStatements=false
4 | formatter.alignSingleLineCaseStatements.maxArrowIndent=40
5 | formatter.compactControlReadability=false
6 | formatter.compactStringConcatenation=false
7 | formatter.doubleIndentClassDeclaration=false
8 | formatter.formatXml=true
9 | formatter.indentLocalDefs=false
10 | formatter.indentPackageBlocks=true
11 | formatter.indentSpaces=2
12 | formatter.indentWithTabs=false
13 | formatter.multilineScaladocCommentsStartOnFirstLine=false
14 | formatter.placeScaladocAsterisksBeneathSecondAsterisk=false
15 | formatter.preserveDanglingCloseParenthesis=false
16 | formatter.preserveSpaceBeforeArguments=false
17 | formatter.rewriteArrowSymbols=false
18 | formatter.spaceBeforeColon=false
19 | formatter.spaceInsideBrackets=false
20 | formatter.spaceInsideParentheses=false
21 | formatter.spacesWithinPatternBinders=true
22 | organizeimports.expandcollapse=expand
23 | organizeimports.groups=java$scala$org$com
24 | organizeimports.wildcards=scalaz$scalaz.Scalaz
25 | syntaxColouring.bracket.bold=false
26 | syntaxColouring.bracket.colour=0,0,0
27 | syntaxColouring.bracket.italic=false
28 | syntaxColouring.bracket.strikethrough=false
29 | syntaxColouring.bracket.underline=false
30 | syntaxColouring.default.bold=false
31 | syntaxColouring.default.colour=0,0,0
32 | syntaxColouring.default.italic=false
33 | syntaxColouring.default.strikethrough=false
34 | syntaxColouring.default.underline=false
35 | syntaxColouring.keyword.bold=true
36 | syntaxColouring.keyword.colour=127,0,85
37 | syntaxColouring.keyword.italic=false
38 | syntaxColouring.keyword.strikethrough=false
39 | syntaxColouring.keyword.underline=false
40 | syntaxColouring.operator.bold=false
41 | syntaxColouring.operator.colour=0,0,0
42 | syntaxColouring.operator.italic=false
43 | syntaxColouring.operator.strikethrough=false
44 | syntaxColouring.operator.underline=false
45 | syntaxColouring.scaladoc.bold=false
46 | syntaxColouring.scaladoc.colour=63,95,191
47 | syntaxColouring.scaladoc.italic=false
48 | syntaxColouring.scaladoc.strikethrough=false
49 | syntaxColouring.scaladoc.underline=false
50 | syntaxColouring.singleLineComment.bold=false
51 | syntaxColouring.singleLineComment.colour=63,127,95
52 | syntaxColouring.singleLineComment.italic=false
53 | syntaxColouring.singleLineComment.strikethrough=false
54 | syntaxColouring.singleLineComment.underline=false
55 | syntaxColouring.string.bold=false
56 | syntaxColouring.string.colour=42,0,255
57 | syntaxColouring.string.italic=false
58 | syntaxColouring.string.strikethrough=false
59 | syntaxColouring.string.underline=false
60 | syntaxColouring.xml.attributeName.bold=false
61 | syntaxColouring.xml.attributeName.colour=127,0,127
62 | syntaxColouring.xml.attributeName.italic=false
63 | syntaxColouring.xml.attributeName.strikethrough=false
64 | syntaxColouring.xml.attributeName.underline=false
65 | syntaxColouring.xml.attributeValue.bold=false
66 | syntaxColouring.xml.attributeValue.colour=42,0,255
67 | syntaxColouring.xml.attributeValue.italic=true
68 | syntaxColouring.xml.attributeValue.strikethrough=false
69 | syntaxColouring.xml.attributeValue.underline=false
70 | syntaxColouring.xml.comment.bold=false
71 | syntaxColouring.xml.comment.colour=63,85,191
72 | syntaxColouring.xml.comment.italic=false
73 | syntaxColouring.xml.comment.strikethrough=false
74 | syntaxColouring.xml.comment.underline=false
75 | syntaxColouring.xml.equals.bold=false
76 | syntaxColouring.xml.equals.colour=0,0,0
77 | syntaxColouring.xml.equals.italic=false
78 | syntaxColouring.xml.equals.strikethrough=false
79 | syntaxColouring.xml.equals.underline=false
80 | syntaxColouring.xml.processingInstruction.bold=false
81 | syntaxColouring.xml.processingInstruction.colour=0,128,128
82 | syntaxColouring.xml.processingInstruction.italic=false
83 | syntaxColouring.xml.processingInstruction.strikethrough=false
84 | syntaxColouring.xml.processingInstruction.underline=false
85 | syntaxColouring.xml.tagDelimiter.bold=false
86 | syntaxColouring.xml.tagDelimiter.colour=0,128,128
87 | syntaxColouring.xml.tagDelimiter.italic=false
88 | syntaxColouring.xml.tagDelimiter.strikethrough=false
89 | syntaxColouring.xml.tagDelimiter.underline=false
90 | syntaxColouring.xml.tagName.bold=false
91 | syntaxColouring.xml.tagName.colour=63,127,127
92 | syntaxColouring.xml.tagName.italic=false
93 | syntaxColouring.xml.tagName.strikethrough=false
94 | syntaxColouring.xml.tagName.underline=false
95 |
--------------------------------------------------------------------------------