From 47582941f65718149fecbc306e4554f421086a48 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 23 Aug 2013 13:14:42 +0800 Subject: [PATCH 01/23] - fixed random crash by ll.lua's assert - fixed cannot load by init_by_lua, because used ngx.var.pid in module file scope, so moved to function run time scope --- lib/resty/mongol/ll.lua | 2 -- lib/resty/mongol/object_id.lua | 23 +++++++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/resty/mongol/ll.lua b/lib/resty/mongol/ll.lua index ec06645..49312c9 100644 --- a/lib/resty/mongol/ll.lua +++ b/lib/resty/mongol/ll.lua @@ -31,7 +31,6 @@ local num_to_le_uint = function ( n , bytes ) for i=1 , bytes do b [ i ] , n = n % 2^8 , floor ( n / 2^8 ) end - assert ( n == 0 ) return strchar ( unpack ( b ) ) end local num_to_le_int = function ( n , bytes ) @@ -57,7 +56,6 @@ local num_to_be_uint = function ( n , bytes ) for i=bytes , 1 , -1 do b [ i ] , n = n % 2^8 , floor ( n / 2^8 ) end - assert ( n == 0 ) return strchar ( unpack ( b ) ) end diff --git a/lib/resty/mongol/object_id.lua b/lib/resty/mongol/object_id.lua index fc3f2bb..88f6b52 100755 --- a/lib/resty/mongol/object_id.lua +++ b/lib/resty/mongol/object_id.lua @@ -46,20 +46,27 @@ local object_id_mt = { } local machineid -if hasposix then - machineid = posix.uname("%n") -else - machineid = assert(io.popen("uname -n")):read("*l") +local function get_os_machineid() + if hasposix then + machineid = posix.uname("%n") + else + machineid = assert(io.popen("uname -n")):read("*l") + end + machineid = ngx.md5_bin(machineid):sub(1, 3) + return machineid end -machineid = ngx.md5_bin(machineid):sub(1, 3) -local pid = num_to_le_uint(ngx.var.pid, 2) +local pid +local function get_os_pid() + pid = num_to_le_uint(ngx.var.pid, 2) + return pid +end local inc = 0 -local function generate_id ( ) +local function generate_id() inc = inc + 1 -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" - return num_to_be_uint ( os.time ( ) , 4 ) .. machineid .. pid .. num_to_be_uint ( inc , 3 ) + return num_to_be_uint(os.time(), 4) .. (machineid or get_os_machineid()) .. (pid or get_os_pid()) .. num_to_be_uint(inc, 3) end local function new_object_id(str) From 9a2724dd5e96c993e850b03f7e76260bbd0d217d Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Sun, 25 Aug 2013 23:23:10 +0800 Subject: [PATCH 02/23] - fixed to_bson not serialize lua table begin from 1 --- lib/resty/mongol/bson.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 8abcf98..e944875 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -157,13 +157,13 @@ end function to_bson(ob) -- Find out if ob if an array; string->value map; or general table local onlyarray = true - local seen_n , high_n = { } , 0 + local seen_n , high_n = { } , 1 local onlystring = true for k , v in pairs ( ob ) do local t_k = type ( k ) onlystring = onlystring and ( t_k == "string" ) if onlyarray then - if t_k == "number" and k >= 0 then + if t_k == "number" and k >= 1 then if k >= high_n then high_n = k seen_n [ k ] = v @@ -186,7 +186,7 @@ function to_bson(ob) elseif onlyarray then local r = { } - local low = 0 + local low = 1 --if seen_n [ 0 ] then low = 0 end for i=low , high_n do r [ i ] = pack ( i , seen_n [ i ] ) From 8317a437d408258a9db8a2e2bbf6fde3f78af99b Mon Sep 17 00:00:00 2001 From: steven123 Date: Thu, 19 Sep 2013 04:34:20 +0800 Subject: [PATCH 03/23] Added 32bit & 64bit int support --- lib/resty/mongol/bson.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index e944875..ffde52a 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -124,7 +124,13 @@ local function pack ( k , v ) local mt = getmetatable ( v ) if ot == "number" then - return "\1" .. k .. "\0" .. to_double ( v ) + if math.floor(v) ~= v then + return "\1" .. k .. "\0" .. to_double ( v ) + elseif v > 2147483647 or v < -2147483648 then -- 64bit + return "\18" .. k .. "\0" .. num_to_le_int ( v , 8 ) + else -- 32bit + return "\16" .. k .. "\0" .. num_to_le_int ( v , 4 ) + end elseif ot == "nil" then return "\10" .. k .. "\0" elseif ot == "string" then From 3d59d5128471e56056e9be2aa796c396653f53e2 Mon Sep 17 00:00:00 2001 From: steven123 Date: Thu, 19 Sep 2013 05:52:16 +0800 Subject: [PATCH 04/23] to_bson userdata = null --- lib/resty/mongol/bson.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index ffde52a..1fa60f8 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -133,6 +133,8 @@ local function pack ( k , v ) end elseif ot == "nil" then return "\10" .. k .. "\0" + elseif ot == "userdata" then + return "\10" .. k .. "\0" elseif ot == "string" then return "\2" .. k .. "\0" .. num_to_le_uint ( #v + 1 ) .. v .. "\0" elseif ot == "boolean" then From abeb135e26b6b5e33f1a0b7684079dea70b8add3 Mon Sep 17 00:00:00 2001 From: steven123 Date: Thu, 19 Sep 2013 06:54:23 +0800 Subject: [PATCH 05/23] check for empty array with ascii 5 if so insert an empty array not object --- lib/resty/mongol/bson.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 1fa60f8..bbea483 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -152,6 +152,9 @@ local function pack ( k , v ) v.st .. v.v elseif ot == "table" then local doc , array = to_bson(v) + if string.byte(doc) == 5 then + return "\4" .. k .. "\0" .. doc + end if array then return "\4" .. k .. "\0" .. doc else From 87f214e6f0207cc7669067d368dcf8eeb3ea5bd2 Mon Sep 17 00:00:00 2001 From: steven123 Date: Sat, 21 Sep 2013 01:14:34 +0800 Subject: [PATCH 06/23] Added query example with order and regex --- Readme.md | 49 +++++++++++++++++++++++++++++++++++++-- lib/resty/mongol/bson.lua | 2 +- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 4eb694d..c724fef 100644 --- a/Readme.md +++ b/Readme.md @@ -234,8 +234,8 @@ Notes Known Issues --------------------------- 1. Auth bson message has reduntant value. -2. Could not inserting a null array, it always inserted as a document. -3. Gridfs_new api only create a meta info in file_col. +2. Gridfs_new api only create a meta info in file_col. + Example --------------------------- @@ -252,6 +252,51 @@ Example r = col:find_one({name="dog"}) ngx.say(r["name"]) + +Example using query and order +--------------------------- + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + ok, err = conn:connect() + if not ok then + ngx.say("connect failed: "..err) + end + + local db = conn:new_db_handle ( "test" ) + col = db:get_col("test") + local sel = {} + sel = {name="dog"} + local field = {} + field['name'] = -1 + id, results, t = col:query({query=sel,orderby=field},returnfields,0,10); + ngx.say(results[1]["name"]) + +Example query with regex and order +--------------------------- + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + ok, err = conn:connect() + if not ok then + ngx.say("connect failed: "..err) + end + + local db = conn:new_db_handle ( "test" ) + col = db:get_col("test") + + local field = {} + field['name'] = -1 + + local regex = {} + regex['$regex'] = 'do.*' + regex['$options'] = 'i' + + local sel = {} + sel = {name=regex} + + id, results, t = col:query({query=sel,orderby=field},returnfields,0,10); + ngx.say(results[1]["name"]) For Test Case -------------------- diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index bbea483..6a91175 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -71,7 +71,7 @@ local function read_document ( get , numerical ) v = nil elseif op == "\16" then --int32 v = le_int_to_num ( get ( 4 ) , 1 , 8 ) - elseif op == "\17" then --int64 + elseif op == "\17" then --int64 // timestamp v = le_int_to_num(get(8), 1, 8) elseif op == "\18" then --int64 v = le_int_to_num(get(8), 1, 8) From 82093f794f4fc00a8248e3c63fd2b372cb0652f5 Mon Sep 17 00:00:00 2001 From: steven123 Date: Sat, 21 Sep 2013 06:26:37 +0800 Subject: [PATCH 07/23] fic bson & add more exaples --- Readme.md | 38 ++++++++++++++++++++++++++++++++++++++ lib/resty/mongol/bson.lua | 6 +++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index c724fef..5943888 100644 --- a/Readme.md +++ b/Readme.md @@ -298,6 +298,44 @@ Example query with regex and order id, results, t = col:query({query=sel,orderby=field},returnfields,0,10); ngx.say(results[1]["name"]) +Example query with or modifier and regex +--------------------------- + local query_object = {} + local or_object = {} + local array_of_or_objects = {} + + local title_regex = {} + title_regex['$regex'] = '^' .. query_string .. '.*' + title_regex['$options'] = 'i' + + local imdb_regex = {} + imdb_regex['$regex'] = '^' .. query_string .. '.*' + imdb_regex['$options'] = 'i' + + local year_regex = {} + year_regex['$regex'] = '^' .. query_string .. '.*' + year_regex['$options'] = 'i' + + local title_object = {title=title_regex} + local imdb_object = {imdb_id=imdb_regex} + local year_object = {year=year_regex} + + array_of_or_objects[1] = title_object + array_of_or_objects[2] = imdb_object + array_of_or_objects[3] = year_object + + or_object['$or'] = array_of_or_objects + query_object['$query'] = query_or + + local returnfields = {id=1,poster_path=1,title=1,popularity=1,vote_average=1,release_date=1} + id, results, t = col:query(query_object,returnfields,0,20); + + if not results then + ngx.say('No results') + end + ngx.say(results[1]['title']) + + For Test Case -------------------- #####mongo config: diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 6a91175..0cf9bcc 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -168,13 +168,13 @@ end function to_bson(ob) -- Find out if ob if an array; string->value map; or general table local onlyarray = true - local seen_n , high_n = { } , 1 + local seen_n , high_n = { } , 0 local onlystring = true for k , v in pairs ( ob ) do local t_k = type ( k ) onlystring = onlystring and ( t_k == "string" ) if onlyarray then - if t_k == "number" and k >= 1 then + if t_k == "number" and k >= 0 then if k >= high_n then high_n = k seen_n [ k ] = v @@ -190,7 +190,7 @@ function to_bson(ob) if onlystring then -- Do string first so the case of an empty table is done properly local r = { } for k , v in pairs ( ob ) do ---ngx.log(ngx.ERR,"="..k..i) + t_insert ( r , pack ( k , v ) ) end m = t_concat ( r ) From 4c35e06c8ab5d51f57a5d38b34b7c552e2309a8e Mon Sep 17 00:00:00 2001 From: steven123 Date: Mon, 23 Sep 2013 14:20:34 +0800 Subject: [PATCH 08/23] Update bson.lua revert back start from 0 for advance queries --- lib/resty/mongol/bson.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 0cf9bcc..157bba2 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -197,7 +197,7 @@ function to_bson(ob) elseif onlyarray then local r = { } - local low = 1 + local low = 0 --if seen_n [ 0 ] then low = 0 end for i=low , high_n do r [ i ] = pack ( i , seen_n [ i ] ) From e053b394eb600b7220b1f1415cf95cb6ff293f12 Mon Sep 17 00:00:00 2001 From: steven123 Date: Mon, 23 Sep 2013 14:39:49 +0800 Subject: [PATCH 09/23] More examples --- Readme.md | 85 ++----------------------------------------------------- 1 file changed, 3 insertions(+), 82 deletions(-) diff --git a/Readme.md b/Readme.md index 5943888..44d8825 100644 --- a/Readme.md +++ b/Readme.md @@ -237,7 +237,7 @@ Known Issues 2. Gridfs_new api only create a meta info in file_col. -Example +Basic Usage --------------------------- local mongo = require "resty.mongol" conn = mongo:new() @@ -253,89 +253,10 @@ Example r = col:find_one({name="dog"}) ngx.say(r["name"]) -Example using query and order ---------------------------- - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - ok, err = conn:connect() - if not ok then - ngx.say("connect failed: "..err) - end - - local db = conn:new_db_handle ( "test" ) - col = db:get_col("test") - local sel = {} - sel = {name="dog"} - local field = {} - field['name'] = -1 - id, results, t = col:query({query=sel,orderby=field},returnfields,0,10); - ngx.say(results[1]["name"]) - -Example query with regex and order ---------------------------- - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - ok, err = conn:connect() - if not ok then - ngx.say("connect failed: "..err) - end - - local db = conn:new_db_handle ( "test" ) - col = db:get_col("test") - - local field = {} - field['name'] = -1 - - local regex = {} - regex['$regex'] = 'do.*' - regex['$options'] = 'i' - - local sel = {} - sel = {name=regex} - - id, results, t = col:query({query=sel,orderby=field},returnfields,0,10); - ngx.say(results[1]["name"]) - -Example query with or modifier and regex ---------------------------- - local query_object = {} - local or_object = {} - local array_of_or_objects = {} - - local title_regex = {} - title_regex['$regex'] = '^' .. query_string .. '.*' - title_regex['$options'] = 'i' - - local imdb_regex = {} - imdb_regex['$regex'] = '^' .. query_string .. '.*' - imdb_regex['$options'] = 'i' - - local year_regex = {} - year_regex['$regex'] = '^' .. query_string .. '.*' - year_regex['$options'] = 'i' - - local title_object = {title=title_regex} - local imdb_object = {imdb_id=imdb_regex} - local year_object = {year=year_regex} - - array_of_or_objects[1] = title_object - array_of_or_objects[2] = imdb_object - array_of_or_objects[3] = year_object - - or_object['$or'] = array_of_or_objects - query_object['$query'] = query_or - - local returnfields = {id=1,poster_path=1,title=1,popularity=1,vote_average=1,release_date=1} - id, results, t = col:query(query_object,returnfields,0,20); - - if not results then - ngx.say('No results') - end - ngx.say(results[1]['title']) +See wiki for advanced examples + For Test Case -------------------- #####mongo config: From 8121adf6fedbe08cd482c3d1d96c57a6972388e9 Mon Sep 17 00:00:00 2001 From: steven123 Date: Wed, 9 Oct 2013 03:42:55 +0800 Subject: [PATCH 10/23] Start lua index from 1 but bson from 0 we start the array count from 0 but need to add 1 to mongo array start from 0 lua from 1 start the array building loop from 0 and compensate it by adding 1 to seen_n and removing 1 from high_n seems to work?? --- lib/resty/mongol/bson.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 157bba2..95ad097 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -168,13 +168,13 @@ end function to_bson(ob) -- Find out if ob if an array; string->value map; or general table local onlyarray = true - local seen_n , high_n = { } , 0 + local seen_n , high_n = { } , 1 local onlystring = true for k , v in pairs ( ob ) do local t_k = type ( k ) onlystring = onlystring and ( t_k == "string" ) if onlyarray then - if t_k == "number" and k >= 0 then + if t_k == "number" and k >= 1 then if k >= high_n then high_n = k seen_n [ k ] = v @@ -198,12 +198,14 @@ function to_bson(ob) local r = { } local low = 0 - --if seen_n [ 0 ] then low = 0 end + --[[ + mongo array start from 0 and lua from 1 + ]]-- for i=low , high_n do - r [ i ] = pack ( i , seen_n [ i ] ) + r [ i ] = pack ( i , seen_n [ i + 1 ] ) end - - m = t_concat ( r , "" , low , high_n ) + local h = high_n - 1 + m = t_concat ( r , "" , low , h ) retarray = true else local ni = 1 From 8bb5e7eaba03ea4ff94251fd5b74335cf5d1ab1e Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 25 Oct 2013 01:23:30 +0800 Subject: [PATCH 11/23] - added Array class support - fixed to_bson incorrectly handle array index --- lib/resty/mongol/bson.lua | 362 +++++++++++++++++++------------------- 1 file changed, 182 insertions(+), 180 deletions(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 95ad097..f488bd1 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -7,10 +7,13 @@ local type = type local tonumber , tostring = tonumber , tostring local t_insert = table.insert local t_concat = table.concat +local t_maxn = table.maxn local strformat = string.format local strmatch = string.match local strbyte = string.byte +local Array = Array + local ll = require ( mod_name .. ".ll" ) local le_uint_to_num = ll.le_uint_to_num local le_int_to_num = ll.le_int_to_num @@ -28,202 +31,201 @@ local object_id_mt = obid.metatable local binary_mt = {} local utc_date = {} - -local function read_document ( get , numerical ) - local bytes = le_uint_to_num ( get ( 4 ) ) - - local ho , hk , hv = false , false , false - local t = { } - while true do - local op = get ( 1 ) - if op == "\0" then break end - - local e_name = read_terminated_string ( get ) - local v - if op == "\1" then -- Double - v = from_double ( get ( 8 ) ) - elseif op == "\2" then -- String - local len = le_uint_to_num ( get ( 4 ) ) - v = get ( len - 1 ) - assert ( get ( 1 ) == "\0" ) - elseif op == "\3" then -- Embedded document - v = read_document ( get , false ) - elseif op == "\4" then -- Array - v = read_document ( get , true ) - elseif op == "\5" then -- Binary - local len = le_uint_to_num ( get ( 4 ) ) - local subtype = get ( 1 ) - v = get ( len ) - elseif op == "\7" then -- ObjectId - v = new_object_id ( get ( 12 ) ) - elseif op == "\8" then -- false - local f = get ( 1 ) - if f == "\0" then - v = false - elseif f == "\1" then - v = true - else - error ( f:byte ( ) ) - end - elseif op == "\9" then -- UTC datetime milliseconds - v = le_uint_to_num ( get ( 8 ) , 1 , 8 ) - elseif op == "\10" then -- Null - v = nil - elseif op == "\16" then --int32 - v = le_int_to_num ( get ( 4 ) , 1 , 8 ) - elseif op == "\17" then --int64 // timestamp - v = le_int_to_num(get(8), 1, 8) - elseif op == "\18" then --int64 - v = le_int_to_num(get(8), 1, 8) - else - error ( "Unknown BSON type: " .. strbyte ( op ) ) - end - - if numerical then - t [ tonumber ( e_name ) ] = v - else - t [ e_name ] = v - end - - -- Check for special universal map - if e_name == "_keys" then - hk = v - elseif e_name == "_vals" then - hv = v - else - ho = true - end - end - - if not ho and hk and hv then - t = { } - for i=1,#hk do - t [ hk [ i ] ] = hv [ i ] - end - end - - return t +local function read_document(get, numerical) + local bytes = le_uint_to_num(get(4)) + + local ho, hk, hv = false, false, false + local t = {} + while true do + local op = get(1) + if op == "\0" then break end + + local e_name = read_terminated_string(get) + local v + if op == "\1" then -- Double + v = from_double(get(8)) + elseif op == "\2" then -- String + local len = le_uint_to_num(get(4)) + v = get(len - 1) + assert(get(1) == "\0") + elseif op == "\3" then -- Embedded document + v = read_document(get, false) + elseif op == "\4" then -- Array + v = read_document(get, true) + if Array then + v = Array(v) + end + elseif op == "\5" then -- Binary + local len = le_uint_to_num(get(4)) + local subtype = get(1) + v = get(len) + elseif op == "\7" then -- ObjectId + v = new_object_id(get(12)) + elseif op == "\8" then -- false + local f = get(1) + if f == "\0" then + v = false + elseif f == "\1" then + v = true + else + error(f:byte()) + end + elseif op == "\9" then -- UTC datetime milliseconds + v = le_uint_to_num(get(8), 1, 8) + elseif op == "\10" then -- Null + v = nil + elseif op == "\16" then --int32 + v = le_int_to_num(get(4), 1, 8) + elseif op == "\17" then --int64 // timestamp + v = le_int_to_num(get(8), 1, 8) + elseif op == "\18" then --int64 + v = le_int_to_num(get(8), 1, 8) + else + error ( "Unknown BSON type: " .. strbyte(op)) + end + + if numerical then + t[tonumber(e_name)] = v + else + t[e_name] = v + end + + -- Check for special universal map + if e_name == "_keys" then + hk = v + elseif e_name == "_vals" then + hv = v + else + ho = true + end + end + + if not ho and hk and hv then + t = {} + for i = 1, #hk do + t[hk[i]] = hv[i] + end + end + + return t end local function get_utc_date(v) - return setmetatable({v = v}, utc_date) + return setmetatable({v = v}, utc_date) end local function get_bin_data(v) - return setmetatable({v = v, st = "\0"}, binary_mt) + return setmetatable({v = v, st = "\0"}, binary_mt) end -local function from_bson ( get ) - local t = read_document ( get , false ) - return t +local function from_bson(get) + return read_document(get, false) end local to_bson -local function pack ( k , v ) - local ot = type ( v ) - local mt = getmetatable ( v ) - - if ot == "number" then - if math.floor(v) ~= v then - return "\1" .. k .. "\0" .. to_double ( v ) - elseif v > 2147483647 or v < -2147483648 then -- 64bit - return "\18" .. k .. "\0" .. num_to_le_int ( v , 8 ) - else -- 32bit - return "\16" .. k .. "\0" .. num_to_le_int ( v , 4 ) - end - elseif ot == "nil" then - return "\10" .. k .. "\0" - elseif ot == "userdata" then - return "\10" .. k .. "\0" - elseif ot == "string" then - return "\2" .. k .. "\0" .. num_to_le_uint ( #v + 1 ) .. v .. "\0" - elseif ot == "boolean" then - if v == false then - return "\8" .. k .. "\0\0" - else - return "\8" .. k .. "\0\1" - end - elseif mt == object_id_mt then - return "\7" .. k .. "\0" .. v.id - elseif mt == utc_date then - return "\9" .. k .. "\0" .. num_to_le_int(v.v, 8) - elseif mt == binary_mt then - return "\5" .. k .. "\0" .. num_to_le_uint(string.len(v.v)) .. - v.st .. v.v - elseif ot == "table" then - local doc , array = to_bson(v) - if string.byte(doc) == 5 then - return "\4" .. k .. "\0" .. doc - end - if array then - return "\4" .. k .. "\0" .. doc - else - return "\3" .. k .. "\0" .. doc - end - else - error ( "Failure converting " .. ot ..": " .. tostring ( v ) ) - end +local function pack(k, v) + local ot = type(v) + local mt = getmetatable(v) + + if ot == "number" then + if math.floor(v) ~= v then + return "\1" .. k .. "\0" .. to_double ( v ) + elseif v > 2147483647 or v < -2147483648 then -- 64bit + return "\18" .. k .. "\0" .. num_to_le_int ( v , 8 ) + else -- 32bit + return "\16" .. k .. "\0" .. num_to_le_int ( v , 4 ) + end + elseif ot == "nil" then + return "\10" .. k .. "\0" + elseif ot == "userdata" then + return "\10" .. k .. "\0" + elseif ot == "string" then + return "\2" .. k .. "\0" .. num_to_le_uint ( #v + 1 ) .. v .. "\0" + elseif ot == "boolean" then + if v == false then + return "\8" .. k .. "\0\0" + else + return "\8" .. k .. "\0\1" + end + elseif mt == object_id_mt then + return "\7" .. k .. "\0" .. v.id + elseif mt == utc_date then + return "\9" .. k .. "\0" .. num_to_le_int(v.v, 8) + elseif mt == binary_mt then + return "\5" .. k .. "\0" .. num_to_le_uint(string.len(v.v)) .. + v.st .. v.v + elseif ot == "table" then + local doc , array = to_bson(v) + if array then + return "\4" .. k .. "\0" .. doc + else + return "\3" .. k .. "\0" .. doc + end + else + error ( "Failure converting " .. ot ..": " .. tostring ( v ) ) + end end function to_bson(ob) - -- Find out if ob if an array; string->value map; or general table - local onlyarray = true - local seen_n , high_n = { } , 1 - local onlystring = true - for k , v in pairs ( ob ) do - local t_k = type ( k ) - onlystring = onlystring and ( t_k == "string" ) - if onlyarray then - if t_k == "number" and k >= 1 then - if k >= high_n then - high_n = k - seen_n [ k ] = v - end - else - onlyarray = false - end - end - if not onlyarray and not onlystring then break end - end - - local retarray , m = false - if onlystring then -- Do string first so the case of an empty table is done properly - local r = { } - for k , v in pairs ( ob ) do - - t_insert ( r , pack ( k , v ) ) + -- Find out if ob if an array; string->value map; or general table + local onlyarray = true + local max = 0 + local onlystring = true + if Array then + if getmetatable(ob) == Array then + max = t_maxn(ob) + onlystring = false + else + onlyarray = false + end + end + if onlystring then + for k, v in pairs(ob) do + local t_k = type(k) + onlystring = onlystring and (t_k == "string") + if onlyarray then + if t_k == "number" and k >= 1 then + if k >= max then + max = k + end + else + onlyarray = false end - m = t_concat ( r ) - elseif onlyarray then - local r = { } - - local low = 0 - --[[ - mongo array start from 0 and lua from 1 - ]]-- - for i=low , high_n do - r [ i ] = pack ( i , seen_n [ i + 1 ] ) - end - local h = high_n - 1 - m = t_concat ( r , "" , low , h ) - retarray = true - else - local ni = 1 - local keys , vals = { } , { } - for k , v in pairs ( ob ) do - keys [ ni ] = k - vals [ ni ] = v - ni = ni + 1 - end - return to_bson ( { _keys = keys , _vals = vals } ) - end - - return num_to_le_uint ( #m + 4 + 1 ) .. m .. "\0" , retarray + end + if not onlyarray and not onlystring then break end + end + end + + local retarray, m = false, nil + if onlystring then -- Do string first so the case of an empty table is done properly + local r = {} + for k, v in pairs(ob) do + t_insert(r, pack(k, v)) + end + m = t_concat(r) + elseif onlyarray then + local r = {} + for i = 1, max do + r[i] = pack(i - 1, ob[i]) + end + m = t_concat(r, "", 1, max) + retarray = true + else + local ni = 1 + local keys, vals = {}, {} + for k, v in pairs(ob) do + keys[ni] = k + vals[ni] = v + ni = ni + 1 + end + return to_bson({_keys = keys, _vals = vals}) + end + return num_to_le_uint(#m + 4 + 1 )..m.."\0", retarray end return { - from_bson = from_bson ; - to_bson = to_bson ; - get_bin_data = get_bin_data; - get_utc_date = get_utc_date; + from_bson = from_bson; + to_bson = to_bson; + get_bin_data = get_bin_data; + get_utc_date = get_utc_date; } From 8192d933c3e79f6949727cc499ebaf91598fe209 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 25 Oct 2013 01:56:27 +0800 Subject: [PATCH 12/23] - fixed read_document, forgot to convert the array to start from 1 --- lib/resty/mongol/bson.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index f488bd1..74bf8c6 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -85,7 +85,7 @@ local function read_document(get, numerical) end if numerical then - t[tonumber(e_name)] = v + t[tonumber(e_name) + 1] = v else t[e_name] = v end From 54978956b48403a6bd59359224c892143c023c48 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 25 Oct 2013 02:40:51 +0800 Subject: [PATCH 13/23] - fixed to_bson dead loop when handle general table --- lib/resty/mongol/bson.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 74bf8c6..3ee113d 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -212,7 +212,12 @@ function to_bson(ob) retarray = true else local ni = 1 - local keys, vals = {}, {} + local keys, vals + if Array then + keys, vals = Array(), Array() + else + keys, vals = {}, {} + end for k, v in pairs(ob) do keys[ni] = k vals[ni] = v From 4cb722694d06b022dcbea6f1fa6ea4c6c6eab969 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 25 Oct 2013 03:00:15 +0800 Subject: [PATCH 14/23] - removed general table support, because it's difficult work with JSON. So, now will convert numerical key to string before store to mongodb. And for the best practice, should avoid to use numerical key. Because there may have conflit, for example: { 'aaa', ["1"] = 'bbb } is unknown behavior --- lib/resty/mongol/bson.lua | 63 ++++++++------------------------------- 1 file changed, 13 insertions(+), 50 deletions(-) diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 3ee113d..7810c13 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -34,7 +34,6 @@ local utc_date = {} local function read_document(get, numerical) local bytes = le_uint_to_num(get(4)) - local ho, hk, hv = false, false, false local t = {} while true do local op = get(1) @@ -89,24 +88,7 @@ local function read_document(get, numerical) else t[e_name] = v end - - -- Check for special universal map - if e_name == "_keys" then - hk = v - elseif e_name == "_vals" then - hv = v - else - ho = true - end end - - if not ho and hk and hv then - t = {} - for i = 1, #hk do - t[hk[i]] = hv[i] - end - end - return t end @@ -167,65 +149,46 @@ local function pack(k, v) end function to_bson(ob) - -- Find out if ob if an array; string->value map; or general table - local onlyarray = true + -- Find out if ob if an array; or a table + local is_array = true local max = 0 - local onlystring = true if Array then if getmetatable(ob) == Array then max = t_maxn(ob) - onlystring = false else - onlyarray = false + is_array = false end - end - if onlystring then + else for k, v in pairs(ob) do local t_k = type(k) - onlystring = onlystring and (t_k == "string") - if onlyarray then + if is_array then if t_k == "number" and k >= 1 then if k >= max then max = k end else - onlyarray = false + is_array = false end end - if not onlyarray and not onlystring then break end + if not is_array then break end end end - local retarray, m = false, nil - if onlystring then -- Do string first so the case of an empty table is done properly - local r = {} - for k, v in pairs(ob) do - t_insert(r, pack(k, v)) - end - m = t_concat(r) - elseif onlyarray then + local m + if is_array then local r = {} for i = 1, max do r[i] = pack(i - 1, ob[i]) end m = t_concat(r, "", 1, max) - retarray = true else - local ni = 1 - local keys, vals - if Array then - keys, vals = Array(), Array() - else - keys, vals = {}, {} - end + local r = {} for k, v in pairs(ob) do - keys[ni] = k - vals[ni] = v - ni = ni + 1 + t_insert(r, pack(tostring(k), v)) end - return to_bson({_keys = keys, _vals = vals}) + m = t_concat(r) end - return num_to_le_uint(#m + 4 + 1 )..m.."\0", retarray + return num_to_le_uint(#m + 4 + 1 )..m.."\0", is_array end return { From 8332d8f99caa1bb198696e3633ecb5891f3974f1 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Wed, 30 Oct 2013 20:53:23 +0800 Subject: [PATCH 15/23] - adjusted object_id tostring and new to use base64 --- lib/resty/mongol/object_id.lua | 87 ++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/lib/resty/mongol/object_id.lua b/lib/resty/mongol/object_id.lua index 88f6b52..9305f04 100755 --- a/lib/resty/mongol/object_id.lua +++ b/lib/resty/mongol/object_id.lua @@ -6,85 +6,88 @@ local strformat = string.format local t_insert = table.insert local t_concat = table.concat -local hasposix , posix = pcall ( require , "posix" ) +local hasposix, posix = pcall(require , "posix") -local ll = require ( mod_name .. ".ll" ) +local ngx_decode_base64 = ngx.decode_base64 +local ngx_encode_base64 = ngx.encode_base64 + +local ll = require(mod_name..".ll") local num_to_le_uint = ll.num_to_le_uint local num_to_be_uint = ll.num_to_be_uint local function _tostring(ob) - local t = {} - for i = 1 , 12 do - t_insert(t, strformat("%02x", strbyte(ob.id, i, i))) - end - return t_concat(t) + return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('*', '/') end local function _get_ts(ob) - return ll.be_uint_to_num(ob.id, 1, 4) + return ll.be_uint_to_num(ob.id, 1, 4) end local function _get_hostname(ob) - local t = {} - for i = 5, 7 do - t_insert(t, strformat("%02x", strbyte(ob.id, i, i))) - end - return t_concat(t) + local t = {} + for i = 5, 7 do + t_insert(t, strformat("%02x", strbyte(ob.id, i, i))) + end + return t_concat(t) end local function _get_pid(ob) - return ll.be_uint_to_num(ob.id, 8, 9) + return ll.be_uint_to_num(ob.id, 8, 9) end local function _get_inc(ob) - return ll.be_uint_to_num(ob.id, 10, 12) + return ll.be_uint_to_num(ob.id, 10, 12) end local object_id_mt = { - __tostring = _tostring; - __eq = function ( a , b ) return a.id == b.id end ; + __tostring = _tostring; + __eq = function ( a , b ) return a.id == b.id end ; } local machineid local function get_os_machineid() - if hasposix then - machineid = posix.uname("%n") - else - machineid = assert(io.popen("uname -n")):read("*l") - end - machineid = ngx.md5_bin(machineid):sub(1, 3) - return machineid + if hasposix then + machineid = posix.uname("%n") + else + machineid = assert(io.popen("uname -n")):read("*l") + end + machineid = ngx.md5_bin(machineid):sub(1, 3) + return machineid end local pid local function get_os_pid() - pid = num_to_le_uint(ngx.var.pid, 2) - return pid + pid = num_to_le_uint(ngx.var.pid, 2) + return pid end local inc = 0 local function generate_id() - inc = inc + 1 - -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" - return num_to_be_uint(os.time(), 4) .. (machineid or get_os_machineid()) .. (pid or get_os_pid()) .. num_to_be_uint(inc, 3) + inc = inc + 1 + -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" + return num_to_be_uint(os.time(), 4) .. (machineid or get_os_machineid()) .. (pid or get_os_pid()) .. num_to_be_uint(inc, 3) end local function new_object_id(str) - if str then - assert(#str == 12) - else - str = generate_id() + local id + if type(str) == 'string' then + if #str == 12 then + id = str + elseif #str == 16 then + id = ngx_decode_base64(sid:gsub('+', '!'):gsub('/', '*')) end - return setmetatable({id = str, - tostring = _tostring, - get_ts = _get_ts, - get_pid = _get_pid, - get_hostname = _get_hostname, - get_inc = _get_inc, - } , object_id_mt) + end + return setmetatable({ + id = id or generate_id(), + tostring = _tostring, + get_ts = _get_ts, + get_pid = _get_pid, + get_hostname = _get_hostname, + get_inc = _get_inc, + }, object_id_mt) end return { - new = new_object_id ; - metatable = object_id_mt ; + new = new_object_id; + metatable = object_id_mt; } From c267f93bf902279ffcceea37ea56f2a58b4e7d08 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Wed, 30 Oct 2013 23:25:51 +0800 Subject: [PATCH 16/23] - changed * to . --- lib/resty/mongol/object_id.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/resty/mongol/object_id.lua b/lib/resty/mongol/object_id.lua index 9305f04..152067d 100755 --- a/lib/resty/mongol/object_id.lua +++ b/lib/resty/mongol/object_id.lua @@ -16,7 +16,7 @@ local num_to_le_uint = ll.num_to_le_uint local num_to_be_uint = ll.num_to_be_uint local function _tostring(ob) - return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('*', '/') + return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('.', '/') end local function _get_ts(ob) @@ -71,10 +71,11 @@ end local function new_object_id(str) local id if type(str) == 'string' then - if #str == 12 then + local len = #str + if len == 12 then id = str - elseif #str == 16 then - id = ngx_decode_base64(sid:gsub('+', '!'):gsub('/', '*')) + elseif len == 16 then + id = ngx_decode_base64(sid:gsub('+', '!'):gsub('/', '.')) end end return setmetatable({ From f813d4dc3be5563ec9572ae228bc43daf5788efc Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 1 Nov 2013 01:10:51 +0800 Subject: [PATCH 17/23] - refactored object_id to ObjectId --- lib/resty/mongol/ObjectId.lua | 97 ++++++++++++++++++++++++++++++++ lib/resty/mongol/bson.lua | 10 ++-- lib/resty/mongol/gridfs.lua | 12 ++-- lib/resty/mongol/gridfs_file.lua | 4 +- lib/resty/mongol/misc.lua | 5 +- lib/resty/mongol/object_id.lua | 94 ------------------------------- 6 files changed, 111 insertions(+), 111 deletions(-) create mode 100755 lib/resty/mongol/ObjectId.lua delete mode 100755 lib/resty/mongol/object_id.lua diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua new file mode 100755 index 0000000..f24537d --- /dev/null +++ b/lib/resty/mongol/ObjectId.lua @@ -0,0 +1,97 @@ +local type = type +local require = require +local assert = assert +local setmetatable = setmetatable + +local string_byte = string.byte +local string_format = string.format +local table_insert = table.insert +local table_concat = table.concat +local os_time = os.time +local io_popen = io.popen + +local hasposix, posix = pcall(require , "posix") + +local ngx = ngx +local ngx_decode_base64 = ngx.decode_base64 +local ngx_encode_base64 = ngx.encode_base64 +local ngx_md5_bin = ngx.md5_bin + +module(...) + +local ll = require(_PACKAGE.."ll") +local num_to_le_uint = ll.num_to_le_uint +local num_to_be_uint = ll.num_to_be_uint +local be_uint_tonum = ll.be_uint_to_num + +local function _tostring(ob) + return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('%.', '/') +end + +local machineid +local function _get_os_machineid() + if hasposix then + machineid = posix.uname("%n") + else + machineid = assert(io_popen("uname -n")):read("*l") + end + machineid = ngx_md5_bin(machineid):sub(1, 3) + return machineid +end + +local pid +local function _get_os_pid() + pid = num_to_le_uint(ngx.var.pid, 2) + return pid +end + +local inc = 0 +local function _generate_id() + inc = inc + 1 + -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" + return num_to_be_uint(os_time(), 4) .. (machineid or _get_os_machineid()) .. (pid or _get_os_pid()) .. num_to_be_uint(inc, 3) +end + +local _new = function(cls, id) + assert(id == nil or type(id) == 'string') + if id then + local len = #id + assert(len == 12 or len == 16) + if len == 16 then + id = ngx_decode_base64((id:gsub('%+', '!'):gsub('/', '.'))) + end + end + local o = { id = id or _generate_id() } + setmetatable(o, cls) + return o +end + +__index = _M +__tostring = _tostring +__eq = function (a, b) + return a.id == b.id +end + +setmetatable(_M, { __call = _new }) + +tostring = _tostring + +function get_ts(ob) + return be_uint_to_num(ob.id, 1, 4) +end + +function get_pid(ob) + return be_uint_to_num(ob.id, 8, 9) +end + +function get_hostname(ob) + local t = {} + for i = 5, 7 do + table_insert(t, string_format("%02x", string_byte(ob.id, i, i))) + end + return table_concat(t) +end + +function get_inc(ob) + return be_uint_to_num(ob.id, 10, 12) +end diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 7810c13..6e590a0 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -22,12 +22,10 @@ local num_to_le_int = ll.num_to_le_int local from_double = ll.from_double local to_double = ll.to_double -local getlib = require ( mod_name .. ".get" ) +local getlib = require(mod_name..".get") local read_terminated_string = getlib.read_terminated_string -local obid = require ( mod_name .. ".object_id" ) -local new_object_id = obid.new -local object_id_mt = obid.metatable +local ObjectId = require(mod_name..".ObjectId") local binary_mt = {} local utc_date = {} @@ -59,7 +57,7 @@ local function read_document(get, numerical) local subtype = get(1) v = get(len) elseif op == "\7" then -- ObjectId - v = new_object_id(get(12)) + v = ObjectId(get(12)) elseif op == "\8" then -- false local f = get(1) if f == "\0" then @@ -129,7 +127,7 @@ local function pack(k, v) else return "\8" .. k .. "\0\1" end - elseif mt == object_id_mt then + elseif mt == ObjectId then return "\7" .. k .. "\0" .. v.id elseif mt == utc_date then return "\9" .. k .. "\0" .. num_to_le_int(v.v, 8) diff --git a/lib/resty/mongol/gridfs.lua b/lib/resty/mongol/gridfs.lua index ff8eb07..2725134 100644 --- a/lib/resty/mongol/gridfs.lua +++ b/lib/resty/mongol/gridfs.lua @@ -1,10 +1,10 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) +local mod_name = (...):match( "^(.*)%..-$" ) local md5 = require "resty.md5" local str = require "resty.string" -local bson = require ( mod_name .. ".bson" ) -local object_id = require ( mod_name .. ".object_id" ) -local gridfs_file= require ( mod_name .. ".gridfs_file" ) +local bson = require(mod_name..".bson") +local ObjectId = require(mod_name..".ObjectId") +local gridfs_file= require(mod_name..".gridfs_file") local gridfs_mt = { } local gridfs = { __index = gridfs_mt } @@ -57,7 +57,7 @@ end function gridfs_mt:new(meta) meta = meta or {} - meta._id = meta._id or object_id.new() + meta._id = meta._id or ObjectId() meta.chunkSize = meta.chunkSize or 256*1024 meta.filename = meta.filename or meta._id:tostring() @@ -81,7 +81,7 @@ end function gridfs_mt:insert(fh, meta, safe) meta = meta or {} meta.chunkSize = meta.chunkSize or 256*1024 - meta._id = meta._id or object_id.new() + meta._id = meta._id or ObjectId() meta.filename = meta.filename or meta._id:tostring() local n = 0 diff --git a/lib/resty/mongol/gridfs_file.lua b/lib/resty/mongol/gridfs_file.lua index 4a99e16..a9497d7 100644 --- a/lib/resty/mongol/gridfs_file.lua +++ b/lib/resty/mongol/gridfs_file.lua @@ -1,8 +1,8 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) +local mod_name = (...):match( "^(.*)%..-$" ) local md5 = require "resty.md5" local str = require "resty.string" -local bson = require ( mod_name .. ".bson" ) +local bson = require(mod_name..".bson") local gridfs_file_mt = { } local gridfs_file = { __index = gridfs_file_mt } diff --git a/lib/resty/mongol/misc.lua b/lib/resty/mongol/misc.lua index e676843..812e9d5 100755 --- a/lib/resty/mongol/misc.lua +++ b/lib/resty/mongol/misc.lua @@ -1,12 +1,11 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) +local mod_name = (...):match("^(.*)%..-$") -local ll = require ( mod_name .. ".ll" ) +local ll = require(mod_name..".ll") local num_to_le_uint = ll.num_to_le_uint local num_to_le_int = ll.num_to_le_int local le_uint_to_num = ll.le_uint_to_num local le_bpeek = ll.le_bpeek - local getmetatable , setmetatable = getmetatable , setmetatable local pairs = pairs local next = next diff --git a/lib/resty/mongol/object_id.lua b/lib/resty/mongol/object_id.lua deleted file mode 100755 index 152067d..0000000 --- a/lib/resty/mongol/object_id.lua +++ /dev/null @@ -1,94 +0,0 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) - -local setmetatable = setmetatable -local strbyte = string.byte -local strformat = string.format -local t_insert = table.insert -local t_concat = table.concat - -local hasposix, posix = pcall(require , "posix") - -local ngx_decode_base64 = ngx.decode_base64 -local ngx_encode_base64 = ngx.encode_base64 - -local ll = require(mod_name..".ll") -local num_to_le_uint = ll.num_to_le_uint -local num_to_be_uint = ll.num_to_be_uint - -local function _tostring(ob) - return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('.', '/') -end - -local function _get_ts(ob) - return ll.be_uint_to_num(ob.id, 1, 4) -end - -local function _get_hostname(ob) - local t = {} - for i = 5, 7 do - t_insert(t, strformat("%02x", strbyte(ob.id, i, i))) - end - return t_concat(t) -end - -local function _get_pid(ob) - return ll.be_uint_to_num(ob.id, 8, 9) -end - -local function _get_inc(ob) - return ll.be_uint_to_num(ob.id, 10, 12) -end - -local object_id_mt = { - __tostring = _tostring; - __eq = function ( a , b ) return a.id == b.id end ; -} - -local machineid -local function get_os_machineid() - if hasposix then - machineid = posix.uname("%n") - else - machineid = assert(io.popen("uname -n")):read("*l") - end - machineid = ngx.md5_bin(machineid):sub(1, 3) - return machineid -end - -local pid -local function get_os_pid() - pid = num_to_le_uint(ngx.var.pid, 2) - return pid -end - -local inc = 0 -local function generate_id() - inc = inc + 1 - -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" - return num_to_be_uint(os.time(), 4) .. (machineid or get_os_machineid()) .. (pid or get_os_pid()) .. num_to_be_uint(inc, 3) -end - -local function new_object_id(str) - local id - if type(str) == 'string' then - local len = #str - if len == 12 then - id = str - elseif len == 16 then - id = ngx_decode_base64(sid:gsub('+', '!'):gsub('/', '.')) - end - end - return setmetatable({ - id = id or generate_id(), - tostring = _tostring, - get_ts = _get_ts, - get_pid = _get_pid, - get_hostname = _get_hostname, - get_inc = _get_inc, - }, object_id_mt) -end - -return { - new = new_object_id; - metatable = object_id_mt; -} From c803a3298f664595a38594dd672451be46404d04 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 1 Nov 2013 01:20:43 +0800 Subject: [PATCH 18/23] - changed . to _ --- lib/resty/mongol/ObjectId.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua index f24537d..a8766e2 100755 --- a/lib/resty/mongol/ObjectId.lua +++ b/lib/resty/mongol/ObjectId.lua @@ -25,7 +25,7 @@ local num_to_be_uint = ll.num_to_be_uint local be_uint_tonum = ll.be_uint_to_num local function _tostring(ob) - return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('%.', '/') + return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('_', '/') end local machineid @@ -58,7 +58,7 @@ local _new = function(cls, id) local len = #id assert(len == 12 or len == 16) if len == 16 then - id = ngx_decode_base64((id:gsub('%+', '!'):gsub('/', '.'))) + id = ngx_decode_base64((id:gsub('%+', '!'):gsub('/', '_'))) end end local o = { id = id or _generate_id() } From 874e82eade8afa0c0058163b2eeb53f0174726ca Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 1 Nov 2013 01:47:25 +0800 Subject: [PATCH 19/23] - revised to return nil with error string instead of assert --- lib/resty/mongol/ObjectId.lua | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua index a8766e2..1256dd9 100755 --- a/lib/resty/mongol/ObjectId.lua +++ b/lib/resty/mongol/ObjectId.lua @@ -53,12 +53,17 @@ local function _generate_id() end local _new = function(cls, id) - assert(id == nil or type(id) == 'string') if id then - local len = #id - assert(len == 12 or len == 16) - if len == 16 then - id = ngx_decode_base64((id:gsub('%+', '!'):gsub('/', '_'))) + if type(id) == 'string' then + local len = #id + if len == 12 then + elseif len == 16 then + id = ngx_decode_base64((id:gsub('%+', '!'):gsub('/', '_'))) + else + return nil, 'expecting string is 12 or 16 length' + end + else + return nil, 'expecting id is string or nil' end end local o = { id = id or _generate_id() } From adead559b6a2d2c2579e6d176bfc633697283a86 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Fri, 1 Nov 2013 03:05:00 +0800 Subject: [PATCH 20/23] - minor change for better coding --- lib/resty/mongol/ObjectId.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua index 1256dd9..83379d4 100755 --- a/lib/resty/mongol/ObjectId.lua +++ b/lib/resty/mongol/ObjectId.lua @@ -24,10 +24,6 @@ local num_to_le_uint = ll.num_to_le_uint local num_to_be_uint = ll.num_to_be_uint local be_uint_tonum = ll.be_uint_to_num -local function _tostring(ob) - return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('_', '/') -end - local machineid local function _get_os_machineid() if hasposix then @@ -52,7 +48,7 @@ local function _generate_id() return num_to_be_uint(os_time(), 4) .. (machineid or _get_os_machineid()) .. (pid or _get_os_pid()) .. num_to_be_uint(inc, 3) end -local _new = function(cls, id) +local function _new(cls, id) if id then if type(id) == 'string' then local len = #id @@ -71,15 +67,19 @@ local _new = function(cls, id) return o end +setmetatable(_M, { __call = _new }) + __index = _M -__tostring = _tostring + +__tostring = function(ob) + return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('_', '/') +end + __eq = function (a, b) return a.id == b.id end -setmetatable(_M, { __call = _new }) - -tostring = _tostring +tostring = __tostring function get_ts(ob) return be_uint_to_num(ob.id, 1, 4) From d440a49dac893cda82cbadf713ecebf869c22dc4 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Mon, 4 Nov 2013 18:24:21 +0800 Subject: [PATCH 21/23] - fixed incorrectly reversed + / and ! _ --- lib/resty/mongol/ObjectId.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua index 83379d4..904c49f 100755 --- a/lib/resty/mongol/ObjectId.lua +++ b/lib/resty/mongol/ObjectId.lua @@ -54,7 +54,7 @@ local function _new(cls, id) local len = #id if len == 12 then elseif len == 16 then - id = ngx_decode_base64((id:gsub('%+', '!'):gsub('/', '_'))) + id = ngx_decode_base64((id:gsub('!', '+'):gsub('_', '/'))) else return nil, 'expecting string is 12 or 16 length' end @@ -72,7 +72,7 @@ setmetatable(_M, { __call = _new }) __index = _M __tostring = function(ob) - return ngx_encode_base64(ob.id):gsub('!', '+'):gsub('_', '/') + return ngx_encode_base64(ob.id):gsub('%+', '!'):gsub('/', '_') end __eq = function (a, b) From 4b0dcfb72661a454f0fab7b6381a72a3575b2298 Mon Sep 17 00:00:00 2001 From: Payne Chu Date: Thu, 19 Dec 2013 14:40:40 +0800 Subject: [PATCH 22/23] - FIX: cjson already referenced to __tojson for serialization instead of __tostring --- lib/resty/mongol/ObjectId.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua index 904c49f..5ee744d 100755 --- a/lib/resty/mongol/ObjectId.lua +++ b/lib/resty/mongol/ObjectId.lua @@ -75,6 +75,8 @@ __tostring = function(ob) return ngx_encode_base64(ob.id):gsub('%+', '!'):gsub('/', '_') end +__tojson = __tostring + __eq = function (a, b) return a.id == b.id end From 07b00b8a958a2ea8ebdbd6684805ab7b7e40091b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20=C5=BBurek?= Date: Fri, 10 Jan 2014 12:01:39 +0100 Subject: [PATCH 23/23] update file_size after write --- lib/resty/mongol/gridfs_file.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/resty/mongol/gridfs_file.lua b/lib/resty/mongol/gridfs_file.lua index a9497d7..4e09ecd 100644 --- a/lib/resty/mongol/gridfs_file.lua +++ b/lib/resty/mongol/gridfs_file.lua @@ -129,6 +129,8 @@ function gridfs_file_mt:write(buf, offset, size) r,err = self.file_col:update({_id = self.files_id},nv, 0, 0, true) if not r then return nil,"write failed: "..err end + + self.file_size = nf end nv["$set"] = {md5 = 0}