1kt = __kyototycoon__ 2db = kt.db 3 4-- prepare secondary indices 5idxdbs = {} 6for dbname, dbobj in pairs(kt.dbs) do 7 if kt.strbwm(dbname, ".kct") then 8 local prefix = kt.regex(dbname, ".*/", "") 9 prefix = kt.regex(dbname, ".kct$", "") 10 if #prefix > 0 then 11 idxdbs[prefix] = dbobj 12 end 13 end 14end 15 16-- set a record 17function set(inmap, outmap) 18 local id = tostring(inmap.id) 19 if not id then 20 return kt.RVEINVALID 21 end 22 local err = false 23 inmap.id = nil 24 local serial = kt.mapdump(inmap) 25 -- visitor function 26 local function visit(key, value, xt) 27 -- clean up indices 28 if value then 29 local obj = kt.mapload(value) 30 for rkey, rvalue in pairs(obj) do 31 local idxdb = idxdbs[rkey] 32 if idxdb then 33 local idxkey = rvalue .. " " .. id 34 if not idxdb:remove(idxkey) then 35 kt.log("error", "removing an index entry failed") 36 err = true 37 end 38 end 39 end 40 end 41 -- insert into indices 42 for rkey, rvalue in pairs(inmap) do 43 local idxdb = idxdbs[rkey] 44 if idxdb then 45 local idxkey = rvalue .. " " .. id 46 if not idxdb:set(idxkey, "") then 47 kt.log("error", "setting an index entry failed") 48 err = true 49 end 50 end 51 end 52 -- insert the serialized data into the main database 53 return serial 54 end 55 -- perform the visitor atomically 56 if not db:accept(id, visit) then 57 kt.log("error", "inserting a record failed") 58 err = true 59 end 60 if err then 61 return kt.EVEINTERNAL 62 end 63 return kt.RVSUCCESS 64end 65 66-- get a record 67function get(inmap, outmap) 68 local id = tostring(inmap.id) 69 if not id then 70 return kt.RVEINVALID 71 end 72 local serial = db:get(id) 73 if not serial then 74 return kt.RVELOGIC 75 end 76 local rec = kt.mapload(serial) 77 for rkey, rvalue in pairs(rec) do 78 outmap[rkey] = rvalue 79 end 80 return kt.RVSUCCESS 81end 82 83-- get heading records 84function head(inmap, outmap) 85 local name = tostring(inmap.name) 86 if not name then 87 return kt.RVEINVALID 88 end 89 local max = tonumber(inmap.max) 90 if not max then 91 max = 10 92 end 93 local idxdb = idxdbs[name] 94 if not idxdb then 95 return kt.RVELOGIC 96 end 97 local cur = idxdb:cursor() 98 cur:jump() 99 local rec 100 while max > 0 do 101 local key = cur:get_key(true) 102 if not key then 103 break 104 end 105 local rkey = kt.regex(key, "[^ ]+ ", "") 106 local rvalue = kt.regex(key, " .*", "") 107 outmap[rkey] = rvalue 108 max = max - 1 109 end 110 cur:disable() 111 return kt.RVSUCCESS 112end 113 114-- get tailing records 115function tail(inmap, outmap) 116 local name = tostring(inmap.name) 117 if not name then 118 return kt.RVEINVALID 119 end 120 local max = tonumber(inmap.max) 121 if not max then 122 max = 10 123 end 124 local idxdb = idxdbs[name] 125 if not idxdb then 126 return kt.RVELOGIC 127 end 128 local cur = idxdb:cursor() 129 cur:jump_back() 130 local rec 131 while max > 0 do 132 local key = cur:get_key() 133 if not key then 134 break 135 end 136 local rkey = kt.regex(key, "[^ ]+ ", "") 137 local rvalue = kt.regex(key, " .*", "") 138 outmap[rkey] = rvalue 139 cur:step_back() 140 max = max - 1 141 end 142 cur:disable() 143 return kt.RVSUCCESS 144end 145 146-- reindex an index 147function reindex(inmap, outmap) 148 local name = tostring(inmap.name) 149 if not name then 150 return kt.RVEINVALID 151 end 152 local idxdb = idxdbs[name] 153 if not idxdb then 154 return kt.RVELOGIC 155 end 156 local err = false 157 -- map function: invert the record data 158 local function map(key, value, emit) 159 local obj = kt.mapload(value) 160 for rkey, rvalue in pairs(obj) do 161 local idxdb = idxdbs[rkey] 162 if idxdb then 163 emit(rvalue, key) 164 end 165 end 166 return true 167 end 168 -- reduce function: insert into the index 169 local function reduce(key, iter) 170 local value 171 while true do 172 value = iter() 173 if not value then 174 break 175 end 176 local idxkey = key .. " " .. value 177 if not idxdb:set(idxkey, "") then 178 kt.log("error", "setting an index entry failed") 179 err = true 180 end 181 end 182 if err then 183 return false 184 end 185 return true 186 end 187 -- clear the index 188 if not idxdb:clear() then 189 kt.log("error", "clearing an index failed") 190 err = true 191 end 192 -- update the index 193 if not db:mapreduce(map, reduce) then 194 kt.log("error", "mapreduce failed") 195 err = true 196 end 197 if err then 198 return kt.EVEINTERNAL 199 end 200 return kt.RVSUCCESS 201end 202