Skip to content

Commit

Permalink
ch09 edits
Browse files Browse the repository at this point in the history
  • Loading branch information
spamegg1 committed Apr 12, 2024
1 parent cf2e085 commit 98c537e
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 181 deletions.
31 changes: 15 additions & 16 deletions src/main/scala/ch09/lmdbSimple/main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import argonaut.*
import Argonaut.*
import LMDB.*

val lineBuffer = stdlib.malloc(1024.toUSize) // 0.5
val getKeyBuffer = stdlib.malloc(512.toUSize) // 0.5
val putKeyBuffer = stdlib.malloc(512.toUSize) // 0.5
val valueBuffer = stdlib.malloc(512.toUSize) // 0.5
val lineBuffer = stdlib.malloc(1024) // 0.5
val getKeyBuffer = stdlib.malloc(512) // 0.5
val putKeyBuffer = stdlib.malloc(512) // 0.5
val valueBuffer = stdlib.malloc(512) // 0.5

@main
def lmdbSimple(args: String*): Unit =
Expand All @@ -39,7 +39,7 @@ def lmdbSimple(args: String*): Unit =
println("done")

object LMDB:
import lmdb_impl.*
import LmdbImpl.*

def open(path: CString): Env =
val envPtr = stackalloc[Env](sizeof[Env])
Expand All @@ -50,8 +50,8 @@ object LMDB:
env

def put(env: Env, key: CString, value: CString): Unit =
val databasePtr = stackalloc[DB]()
val transactionPtr = stackalloc[Transaction]()
val databasePtr = stackalloc[DB](1)
val transactionPtr = stackalloc[Transaction](1)

check(
mdb_transactionn_begin(env, null, 0, transactionPtr),
Expand All @@ -61,20 +61,20 @@ object LMDB:
check(mdb_dbi_open(transaction, null, 0, databasePtr), "mdb_dbi_open")
val db = !databasePtr

val k = stackalloc[Key]()
val k = stackalloc[Key](1)
k._1 = string.strlen(key).toLong + 1.toLong
k._2 = key

val v = stackalloc[Value]()
val v = stackalloc[Value](1)
v._1 = string.strlen(value).toLong + 1.toLong
v._2 = value

check(mdb_put(transaction, db, k, v, 0), "mdb_put")
check(mdb_transactionn_commit(transaction), "mdb_transactionn_commit")

def get(env: Env, key: CString): CString =
val databasePtr = stackalloc[DB]()
val transactionPtr = stackalloc[Transaction]()
val databasePtr = stackalloc[DB](1)
val transactionPtr = stackalloc[Transaction](1)

check(
mdb_transactionn_begin(env, null, 0, transactionPtr),
Expand Down Expand Up @@ -104,15 +104,15 @@ object LMDB:

@link("lmdb")
@extern
object lmdb_impl:
object LmdbImpl:
type Env = Ptr[Byte]
type DB = UInt
def mdb_env_create(env: Ptr[Env]): Int = extern
def mdb_env_open(env: Env, path: CString, flags: Int, mode: Int): Int = extern

type Transaction = Ptr[Byte]
type Key = CStruct2[Long, Ptr[Byte]]
type Value = CStruct2[Long, Ptr[Byte]]

def mdb_env_create(env: Ptr[Env]): Int = extern
def mdb_env_open(env: Env, path: CString, flags: Int, mode: Int): Int = extern
def mdb_transactionn_begin(
env: Env,
parent: Ptr[Byte],
Expand All @@ -133,7 +133,6 @@ object lmdb_impl:
flags: Int
): Int = extern
def mdb_transactionn_commit(transaction: Transaction): Int = extern

def mdb_get(
transaction: Transaction,
db: DB,
Expand Down
73 changes: 35 additions & 38 deletions src/main/scala/ch09/lmdbWeb/http.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,48 @@ import collection.mutable
case class HeaderLine(
key: CString,
value: CString,
key_len: UShort,
value_len: UShort
keyLen: UShort,
valueLen: UShort
)

case class HttpRequest(
method: String,
uri: String,
headers: collection.Map[String, String],
body: String
)

case class HttpResponse(
code: Int,
headers: collection.Map[String, String],
body: String
)

object HTTP:
import LibUV.*
import LibUVConstants.*
import LibUV.*, LibUVConstants.*

type RequestHandler = Function1[HttpRequest, HttpResponse]

val HEADER_COMPLETE_NO_BODY = 0
val HEADERS_INCOMPLETE = -1

val MAX_URI_SIZE = 2048
val MAX_METHOD_SIZE = 8

val method_buffer = malloc(16.toUSize) // 0.5
val uri_buffer = malloc(4096.toUSize) // 0.5
val methodBuffer = malloc(16) // 0.5
val uriBuffer = malloc(4096) // 0.5

def scan_request_line(line: CString): (String, String, Int) =
val lineLen = stackalloc[Int](sizeof[Int])
def scanRequestLine(line: CString): (String, String, Int) =
val lineLen = stackalloc[Int](1)
val scanResult = stdio.sscanf(
line,
c"%s %s %*s\r\n%n",
method_buffer,
uri_buffer,
methodBuffer,
uriBuffer,
lineLen
)
if scanResult == 2 then
(fromCString(method_buffer), fromCString(uri_buffer), !lineLen)
else throw new Exception("bad request line")
if scanResult == 2 then (fromCString(methodBuffer), fromCString(uriBuffer), !lineLen)
else throw Exception("bad request line")

def scan_header_line(
def scanHeaderLine(
line: CString,
outMap: mutable.Map[String, String],
keyEnd: Ptr[Int],
Expand Down Expand Up @@ -85,48 +82,48 @@ object HTTP:
val value = fromCString(startOfValue)
outMap(key) = value
!lineLen
else throw new Exception("bad header line")
else throw Exception("bad header line")

val lineBuffer = malloc(1024.toUSize) // 0.5
val lineBuffer = malloc(1024) // 0.5

def parseRequest(req: CString, size: Long): HttpRequest =
// req(size) = 0 // ensure null termination
req(size) = 0.toByte // ensure null termination
var reqPosition = req
// val lineBuffer = stackalloc[CChar](1024)
val lineLen = stackalloc[Int](sizeof[Int])
val keyEnd = stackalloc[Int](sizeof[Int])
val valueStart = stackalloc[Int](sizeof[Int])
val valueEnd = stackalloc[Int](sizeof[Int])
val lineLen = stackalloc[Int](1)
val keyEnd = stackalloc[Int](1)
val valueStart = stackalloc[Int](1)
val valueEnd = stackalloc[Int](1)
val headers = mutable.Map[String, String]()

val (method, uri, requestLen) = scan_request_line(req)
val (method, uri, requestLen) = scanRequestLine(req)

var bytesRead = requestLen
while bytesRead < size do
reqPosition = req + bytesRead
val parseHeaderResult = scan_header_line(
val parseHeaderResult = scanHeaderLine(
reqPosition,
headers,
keyEnd,
valueStart,
valueEnd,
lineLen
)
if parseHeaderResult < 0 then throw new Exception("HEADERS INCOMPLETE")
if parseHeaderResult < 0 then throw Exception("HEADERS INCOMPLETE")
else if !lineLen - !valueEnd == 2 then bytesRead += parseHeaderResult
else if !lineLen - !valueEnd == 4 then
val remaining = size - bytesRead
val body = fromCString(req + bytesRead)
HttpRequest(method, uri, headers, body)
else throw new Exception("malformed header!")
else throw Exception("malformed header!")

throw new Exception(s"bad scan, exceeded $size bytes")
throw Exception(s"bad scan, exceeded $size bytes")

val keyBuffer = malloc(512.toUSize) // 0.5
val valueBuffer = malloc(512.toUSize) // 0.5
val bodyBuffer = malloc(4096.toUSize) // 0.5
val keyBuffer = malloc(512) // 0.5
val valueBuffer = malloc(512) // 0.5
val bodyBuffer = malloc(4096) // 0.5

def make_response(response: HttpResponse, buffer: Ptr[Buffer]): Unit =
def makeResponse(response: HttpResponse, buffer: Ptr[Buffer]): Unit =
stdio.snprintf(buffer._1, 4096.toUSize, c"HTTP/1.1 200 OK\r\n") // 0.5
var headerPos = 0
val bufferStart = buffer._1
Expand All @@ -138,12 +135,12 @@ object HTTP:
while headerPos < response.headers.size do
val k = headers(headerPos)
val v = response.headers(k)
Zone { // implicit z => // 0.5
Zone: // implicit z => // 0.5
val keyTemp = toCString(k)
val valueTemp = toCString(v)
strncpy(keyBuffer, keyTemp, 512.toUSize) // 0.5
strncpy(valueBuffer, valueTemp, 512.toUSize) // 0.5
}

stdio.snprintf(
lastPos,
bytesRemaining,
Expand All @@ -157,9 +154,9 @@ object HTTP:
lastPos = lastPos + len
headerPos += 1

Zone { // implicit z => // 0.5
Zone: // implicit z => // 0.5
val body = toCString(response.body)
val body_len = strlen(body)
strncpy(bodyBuffer, body, 4096.toUSize) // 0.5
}
val bodyLen = strlen(body)
strncpy(bodyBuffer, body, bodyLen) // 0.5 // was 4096.toUSize

stdio.snprintf(lastPos, bytesRemaining, c"\r\n%s", bodyBuffer)
53 changes: 20 additions & 33 deletions src/main/scala/ch09/lmdbWeb/lmdb.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import argonaut.*
import Argonaut.*

object LMDB:
import lmdb_impl.*
import LmdbImpl.*

def open(path: CString): Env =
val envPtr = stackalloc[Env](sizeof[Env])
Expand All @@ -19,68 +19,64 @@ object LMDB:
check(mdb_env_open(env, path, 0, 420), "mdb_env_open")
env

def getJson[T](env: Env, key: String)(implicit dec: DecodeJson[T]): T =
def getJson[T](env: Env, key: String)(using dec: DecodeJson[T]): T =
val value = getString(env, key)
value.decodeOption[T].get

def putJson[T](env: Env, key: String, value: T)(implicit
enc: EncodeJson[T]
): Unit =
def putJson[T](env: Env, key: String, value: T)(using enc: EncodeJson[T]): Unit =
val valueString = value.asJson.nospaces
putString(env, key, valueString)

def getString(env: Env, key: String): String =
Zone { // implicit z => // 0.5
Zone: // implicit z => // 0.5
val k = toCString(key)
fromCString(get(env, k))
}

def putString(env: Env, key: String, value: String): Unit =
Zone { // implicit z => // 0.5
Zone: // implicit z => // 0.5
val k = toCString(key)
val v = toCString(value)
put(env, k, v)
}

def put(env: Env, key: CString, value: CString): Unit =
val databasePtr = stackalloc[DB](sizeof[DB])
val transactionPtr = stackalloc[Transaction](sizeof[Transaction])
val databasePtr = stackalloc[DB](1)
val transactionPtr = stackalloc[Transaction](1)

check(mdb_txn_begin(env, null, 0, transactionPtr), "mdb_txn_begin")
val transaction = !transactionPtr

check(mdb_dbi_open(transaction, null, 0, databasePtr), "mdb_dbi_open")
val database = !databasePtr

val k = stackalloc[Key](sizeof[Key])
val k = stackalloc[Key](1)
k._1 = string.strlen(key).toLong + 1.toLong
k._2 = key
val v = stackalloc[Value](sizeof[Value])
val v = stackalloc[Value](1)
v._1 = string.strlen(value).toLong + 1.toLong
v._2 = value

check(mdb_put(transaction, database, k, v, 0), "mdb_put")
check(mdb_txn_commit(transaction), "mdb_txn_commit")

def get(env: Env, key: CString): CString =
val databasePtr = stackalloc[DB](sizeof[DB])
val transactionPtr = stackalloc[Transaction](sizeof[Transaction])
val databasePtr = stackalloc[DB](1)
val transactionPtr = stackalloc[Transaction](1)

check(mdb_txn_begin(env, null, 0, transactionPtr), "mdb_txn_begin")
val transaction = !transactionPtr

check(mdb_dbi_open(transaction, null, 0, databasePtr), "mdb_dbi_open")
val database = !databasePtr

val rKey = stackalloc[Key](sizeof[Key])
val rKey = stackalloc[Key](1)
rKey._1 = string.strlen(key).toLong + 1.toLong
rKey._2 = key
val rValue = stackalloc[Value](sizeof[Value])
val rValue = stackalloc[Value](1)

check(mdb_get(transaction, database, rKey, rValue), "mdb_get")

stdio.printf(c"key: %s value: %s\n", rKey._2, rValue._2)
val output = stdlib.malloc(rValue._1.toUSize) // 0.5
val output = stdlib.malloc(rValue._1) // 0.5
string.strncpy(output, rValue._2, rValue._1.toUSize) // 0.5
check(mdb_txn_abort(transaction), "mdb_txn_abort")
output
Expand All @@ -91,26 +87,18 @@ object LMDB:

@link("lmdb")
@extern
object lmdb_impl:
object LmdbImpl:
type Env = Ptr[Byte]
type Transaction = Ptr[Byte]
type DB = UInt
type Key = CStruct2[Long, Ptr[Byte]]
type Value = CStruct2[Long, Ptr[Byte]]

def mdb_env_create(env: Ptr[Env]): Int = extern
def mdb_env_open(env: Env, path: CString, flags: Int, mode: Int): Int = extern
def mdb_txn_begin(
env: Env,
parent: Ptr[Byte],
flags: Int,
tx: Ptr[Transaction]
): Int = extern
def mdb_dbi_open(
tx: Transaction,
name: CString,
flags: Int,
db: Ptr[DB]
): Int = extern
def mdb_txn_begin(env: Env, parent: Ptr[Byte], flags: Int, tx: Ptr[Transaction]): Int =
extern
def mdb_dbi_open(tx: Transaction, name: CString, flags: Int, db: Ptr[DB]): Int = extern
def mdb_put(
tx: Transaction,
db: DB,
Expand All @@ -119,6 +107,5 @@ object lmdb_impl:
flags: Int
): Int = extern
def mdb_txn_commit(tx: Transaction): Int = extern
def mdb_get(tx: Transaction, db: DB, key: Ptr[Key], value: Ptr[Value]): Int =
extern
def mdb_get(tx: Transaction, db: DB, key: Ptr[Key], value: Ptr[Value]): Int = extern
def mdb_txn_abort(tx: Transaction): Int = extern
Loading

0 comments on commit 98c537e

Please sign in to comment.