├── AUTHORS ├── Makefile ├── README.md ├── arcus_set.h ├── arcus_list.h ├── arcus_map.h ├── LICENSE ├── test.cpp └── arcus_mc_node.h /AUTHORS: -------------------------------------------------------------------------------- 1 | KiYeul Lee ; 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | all: 4 | g++ -g -c test.cpp -I/usr/local/include -I/usr/local/include/zookeeper 5 | g++ -o test test.o -lzookeeper_mt -lmhash 6 | 7 | clean: 8 | rm -rf *.o 9 | rm -rf test 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## arcus-cpp-client : Arcus C++ Client 4 | 5 | This is a c++ client driver for Arcus cloud. 6 | 7 | ## Requirement 8 | 9 | This driver requires zookeeper and mhash library. 10 | Install them first. 11 | 12 | 13 | ## Use 14 | 15 | Arcus C++ client is template library so you just should include arcus.h and arcus_mc_node.h to use it. 16 | If you want to use danamic list, dynamic set and dynamic map, include arcus_list.h, arcus_set.h and arcus_map.h and use it. 17 | 18 | You can sample test vectors in test.cpp build it using Makefile and see detail usage in it. 19 | 20 | Visit arcus cache cloud project at github to get more detail information. 21 | https://github.com/naver/arcus 22 | 23 | 24 | ## License 25 | 26 | Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /arcus_set.h: -------------------------------------------------------------------------------- 1 | /* vim: set fdc=2 foldmethod=marker ts=4 tabstop=4 sw=4 : */ 2 | /* 3 | * arcus-cpp-client - Arcus cpp client drvier 4 | * Copyright 2014 NAVER Corp. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __DEF_ARCUS_SET__ 20 | #define __DEF_ARCUS_SET__ 21 | 22 | 23 | #include 24 | 25 | using namespace std; 26 | 27 | #include "arcus.h" 28 | 29 | 30 | struct arcusSetInvalidIterator { }; 31 | 32 | 33 | template 34 | class arcusSet 35 | { 36 | public: 37 | struct iterator/*{{{*/ 38 | { 39 | typedef int difference_type; 40 | typedef T value_type; 41 | typedef T* pointer; 42 | typedef T& reference; 43 | typedef bidirectional_iterator_tag iterator_category; 44 | 45 | iterator(arcusSet* set_, const typename set::iterator& it) 46 | { 47 | this->set_ = set_; 48 | this->it = it; 49 | } 50 | 51 | iterator& operator++() 52 | { 53 | ++it; 54 | return *this; 55 | } 56 | 57 | iterator operator++(int) 58 | { 59 | iterator old(set_, it); 60 | ++it; 61 | return old; 62 | } 63 | 64 | iterator& operator--() 65 | { 66 | --it; 67 | return *this; 68 | } 69 | 70 | iterator operator--(int) 71 | { 72 | iterator old(set_, it); 73 | --it; 74 | return old; 75 | } 76 | 77 | bool operator==(const iterator& rhs) 78 | { 79 | if (set_->on_cache == false) { 80 | throw arcusSetInvalidIterator(); 81 | } 82 | 83 | return (set_ == rhs.set_ && 84 | it == rhs.it); 85 | } 86 | 87 | bool operator!=(const iterator& rhs) 88 | { 89 | if (set_->on_cache == false) { 90 | throw arcusSetInvalidIterator(); 91 | } 92 | 93 | return !(*this == rhs); 94 | } 95 | 96 | T operator*() 97 | { 98 | if (set_->on_cache == false) { 99 | throw arcusSetInvalidIterator(); 100 | } 101 | 102 | return *it; 103 | } 104 | 105 | typename set::iterator it; 106 | arcusSet* set_; 107 | }; 108 | /*}}}*/ 109 | 110 | iterator begin()/*{{{*/ 111 | { 112 | if (on_cache) { 113 | if (time(NULL) > this->next_refresh) { 114 | try { 115 | cache = client->sop_get(key)->get_result >(); 116 | } 117 | catch (arcusCollectionIndexException& e) { 118 | cache.clear(); 119 | } 120 | next_refresh = time(NULL) + cache_time; 121 | } 122 | } 123 | 124 | return iterator(this, cache.begin()); 125 | } 126 | /*}}}*/ 127 | 128 | iterator end()/*{{{*/ 129 | { 130 | if (on_cache) { 131 | if (time(NULL) > this->next_refresh) { 132 | try { 133 | cache = client->sop_get(key)->get_result >(); 134 | } 135 | catch (arcusCollectionIndexException& e) { 136 | cache.clear(); 137 | } 138 | next_refresh = time(NULL) + cache_time; 139 | } 140 | } 141 | 142 | return iterator(this, cache.end()); 143 | } 144 | /*}}}*/ 145 | 146 | public: 147 | arcusSet(arcus* client, const string& key, int cache_time = 0)/*{{{*/ 148 | { 149 | this->client = client; 150 | this->key = key; 151 | this->cache_time = cache_time; 152 | 153 | on_cache = false; 154 | if (cache_time > 0) { 155 | try { 156 | cache = client->sop_get(key)->get_result >(); 157 | } 158 | catch (arcusCollectionIndexException& e) { 159 | cache.clear(); 160 | } 161 | on_cache = true; 162 | } 163 | 164 | next_refresh = time(NULL) + cache_time; 165 | } 166 | /*}}}*/ 167 | 168 | static arcusSet create(arcus* client, const string& key, ARCUS_TYPE type, int exptime = 0, int cache_time = 0)/*{{{*/ 169 | { 170 | arcusFuture ft = client->sop_create(key, type, exptime); 171 | if (ft->get_result() == true) { 172 | arcusSet set_(client, key, cache_time); 173 | return set_; 174 | } 175 | 176 | throw arcusCollectionException(); 177 | } 178 | /*}}}*/ 179 | 180 | static arcusSet get(arcus* client, const string& key, int cache_time = 0)/*{{{*/ 181 | { 182 | arcusSet set_(client, key, cache_time); 183 | return set_; 184 | } 185 | /*}}}*/ 186 | 187 | size_t size()/*{{{*/ 188 | { 189 | if (on_cache) { 190 | if (time(NULL) > next_refresh) { 191 | try { 192 | cache = client->sop_get(key)->get_result >(); 193 | } 194 | catch (arcusCollectionIndexException& e) { 195 | cache.clear(); 196 | } 197 | 198 | next_refresh = time(NULL) + cache_time; 199 | } 200 | 201 | return cache.size(); 202 | } 203 | 204 | try { 205 | return client->sop_get(key)->get_result >().size(); 206 | } 207 | catch (arcusCollectionIndexException& e) { 208 | return 0; 209 | } 210 | } 211 | /*}}}*/ 212 | 213 | iterator find(const T& value)/*{{{*/ 214 | { 215 | if (on_cache) { 216 | if (time(NULL) > next_refresh) { 217 | try { 218 | cache = client->sop_get(key)->get_result >(); 219 | } 220 | catch (arcusCollectionIndexException& e) { 221 | cache.clear(); 222 | } 223 | 224 | next_refresh = time(NULL) + cache_time; 225 | } 226 | 227 | typename set::iterator it = cache.find(value); 228 | return iterator(this, it); 229 | } 230 | 231 | arcusFuture ft = client->sop_exist(key, value); 232 | bool ret = ft->get_result(); 233 | 234 | if (true) { 235 | return iterator(this, cache.begin()); 236 | } 237 | else { 238 | return iterator(this, cache.end()); 239 | } 240 | } 241 | /*}}}*/ 242 | 243 | bool erase(iterator pos)/*{{{*/ 244 | { 245 | return erase(*pos); 246 | } 247 | /*}}}*/ 248 | 249 | bool erase(const T& value)/*{{{*/ 250 | { 251 | arcusFuture ft = client->sop_delete(key, value); 252 | bool ret = ft->get_result(); 253 | 254 | if (ret == true && on_cache) { 255 | if (time(NULL) > next_refresh) { 256 | cache = client->sop_get(key)->get_result >(); 257 | next_refresh = time(NULL) + cache_time; 258 | } 259 | else { 260 | cache.erase(value); 261 | } 262 | } 263 | 264 | return ret; 265 | } 266 | /*}}}*/ 267 | 268 | template 269 | bool insert(InputIterator first, InputIterator last)/*{{{*/ 270 | { 271 | while (first != last) { 272 | arcusFuture ft = client->sop_insert(key, *first); 273 | bool ret = ft->get_result(); 274 | 275 | if (ret == false) { 276 | return false; 277 | } 278 | 279 | cache.insert(*first); 280 | ++first; 281 | } 282 | 283 | return true; 284 | } 285 | /*}}}*/ 286 | 287 | bool insert(const T& value)/*{{{*/ 288 | { 289 | arcusFuture ft = client->sop_insert(key, value); 290 | bool ret = ft->get_result(); 291 | if (ret == false) { 292 | return false; 293 | } 294 | 295 | cache.insert(value); 296 | return true; 297 | } 298 | /*}}}*/ 299 | 300 | void invalidate()/*{{{*/ 301 | { 302 | if (on_cache) { 303 | if (time(NULL) > this->next_refresh) { 304 | try { 305 | cache = client->sop_get(key)->get_result >(); 306 | } 307 | catch (arcusCollectionIndexException& e) { 308 | cache.clear(); 309 | } 310 | next_refresh = time(NULL) + cache_time; 311 | } 312 | } 313 | } 314 | /*}}}*/ 315 | 316 | protected: 317 | arcus* client; 318 | string key; 319 | int cache_time; 320 | set cache; 321 | bool on_cache; 322 | time_t next_refresh; 323 | }; 324 | 325 | 326 | #endif 327 | 328 | 329 | -------------------------------------------------------------------------------- /arcus_list.h: -------------------------------------------------------------------------------- 1 | /* vim: set fdc=2 foldmethod=marker ts=4 tabstop=4 sw=4 : */ 2 | /* 3 | * arcus-cpp-client - Arcus cpp client drvier 4 | * Copyright 2014 NAVER Corp. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __DEF_ARCUS_LIST__ 20 | #define __DEF_ARCUS_LIST__ 21 | 22 | 23 | #include 24 | 25 | using namespace std; 26 | 27 | #include "arcus.h" 28 | 29 | 30 | struct arcusListInvalidIterator { }; 31 | 32 | 33 | 34 | 35 | template 36 | class arcusList 37 | { 38 | public: 39 | struct iterator/*{{{*/ 40 | { 41 | typedef int difference_type; 42 | typedef T value_type; 43 | typedef T* pointer; 44 | typedef T& reference; 45 | typedef bidirectional_iterator_tag iterator_category; 46 | 47 | iterator(arcusList* lst, int idx, const typename list::iterator& it) 48 | { 49 | this->lst = lst; 50 | this->idx = idx; 51 | this->it = it; 52 | size = lst->size(); 53 | } 54 | 55 | iterator& operator++() 56 | { 57 | ++idx, ++it; 58 | return *this; 59 | } 60 | 61 | iterator operator++(int) 62 | { 63 | iterator old(lst, idx, it); 64 | ++idx, ++it; 65 | return old; 66 | } 67 | 68 | iterator& operator--() 69 | { 70 | --idx, --it; 71 | return *this; 72 | } 73 | 74 | iterator operator--(int) 75 | { 76 | iterator old(lst, idx, it); 77 | --idx, --it; 78 | return old; 79 | } 80 | 81 | bool operator==(const iterator& rhs) 82 | { 83 | return (lst == rhs.lst && 84 | idx == rhs.idx); 85 | } 86 | 87 | bool operator!=(const iterator& rhs) 88 | { 89 | return !(*this == rhs); 90 | } 91 | 92 | T operator*() 93 | { 94 | if (lst->on_cache == false) { 95 | throw arcusListInvalidIterator(); 96 | } 97 | 98 | return *it; 99 | } 100 | 101 | int idx; 102 | int size; 103 | typename list::iterator it; 104 | arcusList* lst; 105 | }; 106 | /*}}}*/ 107 | 108 | iterator begin()/*{{{*/ 109 | { 110 | if (on_cache) { 111 | if (time(NULL) > this->next_refresh) { 112 | try { 113 | cache = client->lop_get(key)->get_result >(); 114 | } 115 | catch (arcusCollectionIndexException& e) { 116 | cache.clear(); 117 | } 118 | next_refresh = time(NULL) + cache_time; 119 | } 120 | } 121 | 122 | return iterator(this, 0, cache.begin()); 123 | } 124 | /*}}}*/ 125 | 126 | iterator end()/*{{{*/ 127 | { 128 | if (on_cache) { 129 | if (time(NULL) > this->next_refresh) { 130 | try { 131 | cache = client->lop_get(key)->get_result >(); 132 | } 133 | catch (arcusCollectionIndexException& e) { 134 | cache.clear(); 135 | } 136 | next_refresh = time(NULL) + cache_time; 137 | } 138 | } 139 | 140 | return iterator(this, size(), cache.end()); 141 | } 142 | /*}}}*/ 143 | 144 | public: 145 | arcusList(arcus* client, const string& key, int cache_time = 0)/*{{{*/ 146 | { 147 | this->client = client; 148 | this->key = key; 149 | this->cache_time = cache_time; 150 | 151 | on_cache = false; 152 | if (cache_time > 0) { 153 | try { 154 | cache = client->lop_get(key)->get_result >(); 155 | } 156 | catch (arcusCollectionIndexException& e) { 157 | cache.clear(); 158 | } 159 | on_cache = true; 160 | } 161 | 162 | next_refresh = time(NULL) + cache_time; 163 | } 164 | /*}}}*/ 165 | 166 | static arcusList create(arcus* client, const string& key, ARCUS_TYPE type, int exptime = 0, int cache_time = 0)/*{{{*/ 167 | { 168 | arcusFuture ft = client->lop_create(key, type, exptime); 169 | if (ft->get_result() == true) { 170 | arcusList lst(client, key, cache_time); 171 | return lst; 172 | } 173 | 174 | throw arcusCollectionException(); 175 | } 176 | /*}}}*/ 177 | 178 | static arcusList get(arcus* client, const string& key, int cache_time = 0)/*{{{*/ 179 | { 180 | arcusList lst(client, key, cache_time); 181 | return lst; 182 | } 183 | /*}}}*/ 184 | 185 | size_t size()/*{{{*/ 186 | { 187 | if (on_cache) { 188 | if (time(NULL) > next_refresh) { 189 | try { 190 | cache = client->lop_get(key)->get_result >(); 191 | } 192 | catch (arcusCollectionIndexException& e) { 193 | cache.clear(); 194 | } 195 | 196 | next_refresh = time(NULL) + cache_time; 197 | } 198 | 199 | return cache.size(); 200 | } 201 | 202 | try { 203 | return client->lop_get(key)->get_result >().size(); 204 | } 205 | catch (arcusCollectionIndexException& e) { 206 | return 0; 207 | } 208 | } 209 | /*}}}*/ 210 | 211 | bool push_front(const T& value)/*{{{*/ 212 | { 213 | arcusFuture ft = client->lop_insert(key, 0, value); 214 | bool ret = ft->get_result(); 215 | 216 | if (ret == true && on_cache) { 217 | if (time(NULL) > next_refresh) { 218 | try { 219 | cache = client->lop_get(key)->get_result >(); 220 | } 221 | catch (arcusCollectionIndexException& e) { 222 | cache.clear(); 223 | } 224 | next_refresh = time(NULL) + cache_time; 225 | } 226 | else { 227 | cache.push_front(value); 228 | } 229 | } 230 | 231 | return ret; 232 | } 233 | /*}}}*/ 234 | 235 | bool pop_front()/*{{{*/ 236 | { 237 | bool ret = client->lop_delete(key, 0, 0)->get_result(); 238 | 239 | if (ret == true && on_cache) { 240 | if (time(NULL) > next_refresh) { 241 | try { 242 | cache = client->lop_get(key)->get_result >(); 243 | } 244 | catch (arcusCollectionIndexException& e) { 245 | cache.clear(); 246 | } 247 | next_refresh = time(NULL) + cache_time; 248 | } 249 | else { 250 | cache.pop_front(); 251 | } 252 | } 253 | 254 | return ret; 255 | } 256 | /*}}}*/ 257 | 258 | bool push_back(const T& value)/*{{{*/ 259 | { 260 | arcusFuture ft = client->lop_insert(key, -1, value); 261 | bool ret = ft->get_result(); 262 | 263 | if (ret == true && on_cache) { 264 | if (time(NULL) > next_refresh) { 265 | cache = client->lop_get(key)->get_result >(); 266 | next_refresh = time(NULL) + cache_time; 267 | } 268 | else { 269 | cache.push_back(value); 270 | } 271 | } 272 | 273 | return ret; 274 | } 275 | /*}}}*/ 276 | 277 | bool pop_back()/*{{{*/ 278 | { 279 | bool ret = client->lop_delete(key, -1, -1)->get_result(); 280 | 281 | if (ret == true && on_cache) { 282 | if (time(NULL) > next_refresh) { 283 | cache = client->lop_get(key)->get_result >(); 284 | next_refresh = time(NULL) + cache_time; 285 | } 286 | else { 287 | cache.pop_back(); 288 | } 289 | } 290 | 291 | return ret; 292 | } 293 | /*}}}*/ 294 | 295 | bool erase(iterator first, iterator last)/*{{{*/ 296 | { 297 | arcusFuture ft = client->lop_delete(key, first.idx, last.idx-1); 298 | bool ret = ft->get_result(); 299 | 300 | if (ret == true && on_cache) { 301 | if (time(NULL) > next_refresh) { 302 | cache = client->lop_get(key)->get_result >(); 303 | next_refresh = time(NULL) + cache_time; 304 | } 305 | else { 306 | cache.erase(first.it, last.it); 307 | } 308 | } 309 | 310 | return ret; 311 | } 312 | /*}}}*/ 313 | 314 | template 315 | bool insert(iterator position, InputIterator first, InputIterator last)/*{{{*/ 316 | { 317 | while (first != last) { 318 | arcusFuture ft = client->lop_insert(key, position.idx, *first); 319 | bool ret = ft->get_result(); 320 | 321 | if (ret == false) { 322 | return false; 323 | } 324 | 325 | position.it = cache.insert(position.it, *first); 326 | 327 | ++position; 328 | ++first; 329 | 330 | } 331 | 332 | return true; 333 | } 334 | /*}}}*/ 335 | 336 | void invalidate()/*{{{*/ 337 | { 338 | if (on_cache) { 339 | if (time(NULL) > this->next_refresh) { 340 | try { 341 | cache = client->lop_get(key)->get_result >(); 342 | } 343 | catch (arcusCollectionIndexException& e) { 344 | cache.clear(); 345 | } 346 | next_refresh = time(NULL) + cache_time; 347 | } 348 | } 349 | } 350 | /*}}}*/ 351 | 352 | protected: 353 | arcus* client; 354 | string key; 355 | int cache_time; 356 | list cache; 357 | bool on_cache; 358 | time_t next_refresh; 359 | }; 360 | 361 | 362 | #endif 363 | 364 | 365 | -------------------------------------------------------------------------------- /arcus_map.h: -------------------------------------------------------------------------------- 1 | /* vim: set fdc=2 foldmethod=marker ts=4 tabstop=4 sw=4 : */ 2 | /* 3 | * arcus-cpp-client - Arcus cpp client drvier 4 | * Copyright 2014 NAVER Corp. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __DEF_ARCUS_MAP__ 20 | #define __DEF_ARCUS_MAP__ 21 | 22 | 23 | #include 24 | 25 | using namespace std; 26 | 27 | #include "arcus.h" 28 | 29 | 30 | class arcusMapInvalidIterator {}; 31 | class arcusMapNotCached {}; 32 | class arcusMapException {}; 33 | 34 | 35 | template struct arcusBKeyMinMax/*{{{*/ 36 | { 37 | static K get_min_key() { assert(false); } 38 | static K get_max_key() { assert(false); } 39 | }; 40 | /*}}}*/ 41 | 42 | template <> struct arcusBKeyMinMax/*{{{*/ 43 | { 44 | static uint64_t get_min_key() 45 | { 46 | return arcusBKey::get_min_long_key().l_key; 47 | } 48 | 49 | static uint64_t get_max_key() 50 | { 51 | return arcusBKey::get_max_long_key().l_key; 52 | } 53 | }; 54 | /*}}}*/ 55 | 56 | template <> struct arcusBKeyMinMax >/*{{{*/ 57 | { 58 | static vector get_min_key() 59 | { 60 | return arcusBKey::get_min_hex_key().h_key; 61 | } 62 | 63 | static vector get_max_key() 64 | { 65 | return arcusBKey::get_max_hex_key().h_key; 66 | } 67 | }; 68 | /*}}}*/ 69 | 70 | 71 | 72 | template 73 | class arcusMap 74 | { 75 | public: 76 | struct iterator/*{{{*/ 77 | { 78 | typedef int difference_type; 79 | typedef pair value_type; 80 | typedef pair* pointer; 81 | typedef pair& reference; 82 | typedef bidirectional_iterator_tag iterator_category; 83 | 84 | iterator(arcusMap* map_, const K& bkey) 85 | { 86 | this->map_ = map_; 87 | this->bkey = bkey; 88 | this->on_cache = false; 89 | } 90 | 91 | iterator(arcusMap* map_, const typename map >::iterator& it) 92 | { 93 | this->map_ = map_; 94 | this->it = it; 95 | this->on_cache = true; 96 | } 97 | 98 | 99 | iterator& operator++() 100 | { 101 | if (on_cache) { 102 | ++it; 103 | } 104 | else { 105 | throw arcusMapNotCached(); 106 | } 107 | 108 | return *this; 109 | } 110 | 111 | iterator operator++(int) 112 | { 113 | if (on_cache) { 114 | iterator old(map_, it); 115 | ++it; 116 | return old; 117 | } 118 | else { 119 | throw arcusMapNotCached(); 120 | } 121 | } 122 | 123 | iterator& operator--() 124 | { 125 | if (on_cache) { 126 | --it; 127 | } 128 | else { 129 | throw arcusMapNotCached(); 130 | } 131 | 132 | return *this; 133 | } 134 | 135 | iterator operator--(int) 136 | { 137 | if (on_cache) { 138 | iterator old(map_, it); 139 | --it; 140 | return old; 141 | } 142 | else { 143 | throw arcusMapNotCached(); 144 | } 145 | } 146 | 147 | bool operator==(const iterator& rhs) 148 | { 149 | if (map_->on_cache) { 150 | return (map_ == rhs.map_ && it == rhs.it); 151 | } 152 | else { 153 | return (map_ == rhs.map_ && bkey == rhs.bkey); 154 | } 155 | } 156 | 157 | bool operator!=(const iterator& rhs) 158 | { 159 | return !(*this == rhs); 160 | } 161 | 162 | pair > operator*() 163 | { 164 | if (map_->on_cache) { 165 | return pair >(it->first, it->second); 166 | } 167 | 168 | return pair >(bkey, arcusBopItem()); 169 | } 170 | 171 | K first() 172 | { 173 | if (map_->on_cache) { 174 | return it->first; 175 | } 176 | 177 | return bkey; 178 | } 179 | 180 | V second() 181 | { 182 | if (map_->on_cache == false) { 183 | throw arcusMapNotCached(); 184 | } 185 | 186 | return it->second; 187 | } 188 | 189 | K bkey; 190 | typename map >::iterator it; 191 | arcusMap* map_; 192 | bool on_cache; 193 | }; 194 | /*}}}*/ 195 | 196 | iterator begin()/*{{{*/ 197 | { 198 | if (on_cache) { 199 | if (time(NULL) > this->next_refresh) { 200 | recache(); 201 | } 202 | 203 | return iterator(this, cache.begin()); 204 | } 205 | 206 | return iterator(this, arcusBKeyMinMax::get_min_key()); 207 | } 208 | /*}}}*/ 209 | 210 | iterator end()/*{{{*/ 211 | { 212 | if (on_cache) { 213 | if (time(NULL) > this->next_refresh) { 214 | recache(); 215 | } 216 | 217 | return iterator(this, cache.end()); 218 | } 219 | 220 | return iterator(this, arcusBKeyMinMax::get_max_key()); 221 | } 222 | /*}}}*/ 223 | 224 | iterator lower_bound(const K& bkey)/*{{{*/ 225 | { 226 | if (on_cache) { 227 | if (time(NULL) > this->next_refresh) { 228 | recache(); 229 | } 230 | 231 | return iterator(this, cache.lower_bound(bkey)); 232 | } 233 | 234 | return iterator(this, bkey); 235 | } 236 | /*}}}*/ 237 | 238 | public: 239 | arcusMap(arcus* client, const string& key, int cache_time = 0)/*{{{*/ 240 | { 241 | this->client = client; 242 | this->key = key; 243 | this->cache_time = cache_time; 244 | 245 | on_cache = false; 246 | next_refresh = 0; 247 | if (cache_time > 0) { 248 | on_cache = true; 249 | recache(); 250 | } 251 | } 252 | /*}}}*/ 253 | 254 | static arcusMap create(arcus* client, const string& key, ARCUS_TYPE type, int exptime = 0, int cache_time = 0)/*{{{*/ 255 | { 256 | arcusFuture ft = client->bop_create(key, type, exptime); 257 | if (ft->get_result() == true) { 258 | arcusMap map_(client, key, cache_time); 259 | return map_; 260 | } 261 | 262 | throw arcusCollectionException(); 263 | } 264 | /*}}}*/ 265 | 266 | static arcusMap get(arcus* client, const string& key, int cache_time = 0)/*{{{*/ 267 | { 268 | arcusMap map_(client, key, cache_time); 269 | return map_; 270 | } 271 | /*}}}*/ 272 | 273 | size_t size()/*{{{*/ 274 | { 275 | if (on_cache) { 276 | if (time(NULL) > next_refresh) { 277 | recache(); 278 | } 279 | 280 | return cache.size(); 281 | } 282 | 283 | try { 284 | arcusFuture ft = client->bop_get(key, arcusBKeyMinMax::get_min_key(), arcusBKeyMinMax::get_max_key()); 285 | return ft->get_result_map().size(); 286 | } 287 | catch (arcusCollectionIndexException& e) { 288 | return 0; 289 | } 290 | } 291 | /*}}}*/ 292 | 293 | bool erase(iterator first, iterator last)/*{{{*/ 294 | { 295 | arcusFuture ft = client->bop_delete(key, first.first(), last.last()); 296 | bool ret = ft->get_result(); 297 | 298 | if (ret == true && on_cache) { 299 | if (time(NULL) > next_refresh) { 300 | recache(); 301 | } 302 | else { 303 | cache.erase(first.it, last.it); 304 | } 305 | } 306 | 307 | return ret; 308 | } 309 | /*}}}*/ 310 | 311 | template 312 | bool insert(InputIterator first, InputIterator last)/*{{{*/ 313 | { 314 | while (first != last) { 315 | arcusFuture ft = client->bop_insert(key, first->first, first->second.value, first->second.eflag); 316 | bool ret = ft->get_result(); 317 | 318 | if (ret == false) { 319 | return false; 320 | } 321 | 322 | if (on_cache) { 323 | if (time(NULL) > this->next_refresh) { 324 | recache(); 325 | } 326 | 327 | cache[first->first] = first->second; 328 | } 329 | 330 | ++first; 331 | } 332 | 333 | return true; 334 | } 335 | /*}}}*/ 336 | 337 | bool insert(const K& bkey, const V& value, const arcusEflag& flag)/*{{{*/ 338 | { 339 | arcusFuture ft = client->bop_insert(key, bkey, value, flag); 340 | bool ret = ft->get_result(); 341 | 342 | if (ret == false) { 343 | return false; 344 | } 345 | 346 | if (on_cache) { 347 | if (time(NULL) > this->next_refresh) { 348 | recache(); 349 | } 350 | 351 | cache[key] = arcusBopItem(value, flag); 352 | } 353 | 354 | return true; 355 | } 356 | /*}}}*/ 357 | 358 | const arcusBopItem& operator[](const K& bkey)/*{{{*/ 359 | { 360 | if (on_cache) { 361 | if (time(NULL) > this->next_refresh) { 362 | recache(); 363 | } 364 | 365 | return cache[bkey]; 366 | } 367 | else { 368 | arcusFuture ft = client->bop_get(key, bkey, bkey); 369 | map > ret = ft->get_result_map(); 370 | return ret[bkey]; 371 | } 372 | } 373 | /*}}}*/ 374 | 375 | void invalidate()/*{{{*/ 376 | { 377 | if (on_cache) { 378 | recache(); 379 | } 380 | } 381 | /*}}}*/ 382 | 383 | 384 | private: 385 | void recache()/*{{{*/ 386 | { 387 | try { 388 | arcusFuture ft = client->bop_get(key, arcusBKeyMinMax::get_min_key(), arcusBKeyMinMax::get_max_key()); 389 | cache = ft->get_result_map(); 390 | } 391 | catch (arcusCollectionIndexException& e) { 392 | cache.clear(); 393 | } 394 | 395 | next_refresh = time(NULL) + cache_time; 396 | } 397 | /*}}}*/ 398 | 399 | protected: 400 | arcus* client; 401 | string key; 402 | int cache_time; 403 | map > cache; 404 | bool on_cache; 405 | time_t next_refresh; 406 | }; 407 | 408 | 409 | #endif 410 | 411 | 412 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set fdc=2 foldmethod=marker ts=4 tabstop=4 sw=4 : */ 2 | /* 3 | * arcus-cpp-client - Arcus cpp client drvier 4 | * Copyright 2014 NAVER Corp. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | 25 | #include "arcus.h" 26 | #include "arcus_mc_node.h" 27 | #include "arcus_list.h" 28 | #include "arcus_set.h" 29 | #include "arcus_map.h" 30 | 31 | template void print(T value)/*{{{*/ 32 | { 33 | printf("## result: %s\n", lexical_cast(value).c_str()); 34 | } 35 | /*}}}*/ 36 | 37 | template void print(list value)/*{{{*/ 38 | { 39 | typename list::iterator it; 40 | 41 | printf("## list: "); 42 | for (it = value.begin(); it != value.end(); ++it) { 43 | printf("%s, ", lexical_cast(*it).c_str()); 44 | } 45 | printf("\n"); 46 | } 47 | /*}}}*/ 48 | 49 | template void print(vector value)/*{{{*/ 50 | { 51 | typename vector::iterator it; 52 | 53 | printf("## vector: "); 54 | for (it = value.begin(); it != value.end(); ++it) { 55 | printf("%s, ", lexical_cast(*it).c_str()); 56 | } 57 | printf("\n"); 58 | } 59 | /*}}}*/ 60 | 61 | template void print(set value)/*{{{*/ 62 | { 63 | typename set::iterator it; 64 | 65 | printf("## set: "); 66 | for (it = value.begin(); it != value.end(); ++it) { 67 | printf("%s, ", lexical_cast(*it).c_str()); 68 | } 69 | printf("\n"); 70 | } 71 | /*}}}*/ 72 | 73 | template void print(map > value)/*{{{*/ 74 | { 75 | typename map >::iterator it; 76 | 77 | printf("## map: "); 78 | for (it = value.begin(); it != value.end(); ++it) { 79 | string key = lexical_cast(it->first); 80 | printf("[%s:%s (%s)], ", 81 | key.c_str(), 82 | lexical_cast(it->second.value).c_str(), 83 | it->second.eflag_hex_str().c_str()); 84 | } 85 | printf("\n"); 86 | } 87 | /*}}}*/ 88 | 89 | template void print(map > > value)/*{{{*/ 90 | { 91 | typename map > >::iterator it_1; 92 | typename map >::iterator it_2; 93 | 94 | printf("## mget: "); 95 | for (it_1 = value.begin(); it_1 != value.end(); ++it_1) { 96 | string key = lexical_cast(it_1->first); 97 | 98 | for (it_2 = it_1->second.begin(); it_2 != it_1->second.end(); ++it_2) { 99 | string bkey = lexical_cast(it_2->first); 100 | printf("[%s-%s:%s (%s)], ", 101 | key.c_str(), 102 | bkey.c_str(), 103 | lexical_cast(it_2->second.value).c_str(), 104 | it_2->second.eflag_hex_str().c_str()); 105 | } 106 | } 107 | printf("\n"); 108 | } 109 | /*}}}*/ 110 | 111 | template void print_vmap(map > value)/*{{{*/ 112 | { 113 | typename map >::iterator it; 114 | 115 | printf("## map: "); 116 | for (it = value.begin(); it != value.end(); ++it) { 117 | string key = util.vec2hstr(it->first); 118 | 119 | printf("[%s:%s (%s)], ", 120 | key.c_str(), 121 | lexical_cast(it->second.value).c_str(), 122 | it->second.eflag_hex_str().c_str()); 123 | } 124 | printf("\n"); 125 | } 126 | /*}}}*/ 127 | 128 | template void print(multimap > value)/*{{{*/ 129 | { 130 | typename multimap >::iterator it; 131 | 132 | printf("## multimap: "); 133 | for (it = value.begin(); it != value.end(); ++it) { 134 | string key = lexical_cast(it->first); 135 | printf("[%s:%s (%s)], ", 136 | key.c_str(), 137 | lexical_cast(it->second.value).c_str(), 138 | it->second.eflag_hex_str().c_str()); 139 | } 140 | printf("\n"); 141 | } 142 | /*}}}*/ 143 | 144 | template void print_vmap(multimap > value)/*{{{*/ 145 | { 146 | typename multimap >::iterator it; 147 | 148 | printf("## multimap: "); 149 | for (it = value.begin(); it != value.end(); ++it) { 150 | string key = util.vec2hstr(it->first); 151 | 152 | printf("[%s:%s (%s)], ", 153 | key.c_str(), 154 | lexical_cast(it->second.value).c_str(), 155 | it->second.eflag_hex_str().c_str()); 156 | } 157 | printf("\n"); 158 | } 159 | /*}}}*/ 160 | 161 | 162 | int main(int argc, char* argv[]) 163 | { 164 | int i, j, idx; 165 | if (argc < 3) { 166 | return 0; 167 | } 168 | 169 | arcusNodeAllocator* allocator = new arcusMCNodeAllocator(new arcusTranscoder()); 170 | arcusLocator* locator = new arcusLocator(allocator); 171 | arcus* client = new arcus(locator); 172 | 173 | client->connect(argv[1], argv[2]); 174 | 175 | //arcus_log(NULL); 176 | 177 | arcusFuture ret; 178 | 179 | /*************************************************************************************************** 180 | * 181 | * TEST 1: primitive type 182 | * 183 | ***************************************************************************************************/ 184 | if (true) { 185 | ret = client->set("test:string1", "test...", 3); 186 | print(ret->get_result()); 187 | assert (ret->get_result() == true); 188 | 189 | ret = client->get("test:string1"); 190 | print(ret->get_result()); 191 | assert (ret->get_result() == "test..."); 192 | 193 | ret = client->set("test:string2", "test...2", 3); 194 | print(ret->get_result()); 195 | assert (ret->get_result() == true); 196 | 197 | ret = client->get("test:string2"); 198 | print(ret->get_result()); 199 | assert (ret->get_result() == "test...2"); 200 | 201 | ret = client->set("test:int", 1, 3); 202 | print(ret->get_result()); 203 | assert (ret->get_result() == true); 204 | 205 | ret = client->get("test:int"); 206 | print(ret->get_result()); 207 | assert (ret->get_result() == 1); 208 | 209 | ret = client->set("test:float", 1.2, 3); 210 | print(ret->get_result()); 211 | assert (ret->get_result() == true); 212 | 213 | ret = client->get("test:float"); 214 | print(ret->get_result()); 215 | assert (ret->get_result() == 1.2); 216 | 217 | ret = client->set("test:bool", true, 3); 218 | print(ret->get_result()); 219 | assert (ret->get_result() == true); 220 | 221 | ret = client->get("test:bool"); 222 | print(ret->get_result()); 223 | assert (ret->get_result() == true); 224 | 225 | ptime now = microsec_clock::local_time(); 226 | ret = client->set("test:date", now, 3); 227 | print(ret->get_result()); 228 | assert (ret->get_result() == true); 229 | 230 | ret = client->get("test:date"); 231 | print(ret->get_result()); 232 | print(now); 233 | assert ((ret->get_result() - now) < millisec(1)); 234 | 235 | vector array; 236 | for (i=0; i<10; i++) array.push_back('a' + i); 237 | 238 | ret = client->set("test:bytearray", array, 3); 239 | print(ret->get_result()); 240 | assert (ret->get_result() == true); 241 | 242 | ret = client->get("test:bytearray"); 243 | vector array_ret = ret->get_result >(); 244 | print(array_ret); 245 | assert (ret->get_result >() == array); 246 | 247 | 248 | ret = client->set("test:incr", "1", 3); 249 | print(ret->get_result()); 250 | assert (ret->get_result() == true); 251 | 252 | ret = client->incr("test:incr", 10); 253 | print(ret->get_result()); 254 | assert (ret->get_result() == 11); 255 | 256 | ret = client->decr("test:incr", 3); 257 | print(ret->get_result()); 258 | assert (ret->get_result() == 11-3); 259 | 260 | ret = client->decr("test:incr", 100); 261 | print(ret->get_result()); 262 | assert (ret->get_result() == 0); // minimum value is 0 263 | } 264 | 265 | 266 | /*************************************************************************************************** 267 | * 268 | * TEST 2: list 269 | * 270 | ***************************************************************************************************/ 271 | if (false) { 272 | list l_s_src; 273 | list l_s; 274 | 275 | ret = client->lop_create("test:list_1", FLAG_STRING, 3); 276 | print(ret->get_result()); 277 | assert (ret->get_result() == true); 278 | 279 | for (i=0; i<6; i++) { 280 | char buff[256]; 281 | sprintf(buff, "item %d", i); 282 | l_s_src.push_back(buff); 283 | } 284 | 285 | for (list::iterator it = l_s_src.begin(); it != l_s_src.end(); ++it) { 286 | ret = client->lop_insert("test:list_1", -1, *it); 287 | print(ret->get_result()); 288 | assert (ret->get_result() == true); 289 | } 290 | 291 | ret = client->lop_get("test:list_1", 0, -1); 292 | l_s = ret->get_result >(); 293 | print(l_s); 294 | assert (l_s == l_s_src); 295 | 296 | ret = client->lop_get("test:list_1", 2, 4); 297 | l_s = ret->get_result >(); 298 | print(l_s); 299 | //assert (l_s == l_s_src[2:4+1]); 300 | 301 | ret = client->lop_get("test:list_1", 1, -2); 302 | l_s = ret->get_result >(); 303 | print(l_s); 304 | //assert (l_s == src[1:-2+1]); 305 | } 306 | 307 | 308 | 309 | /*************************************************************************************************** 310 | * 311 | * TEST 3: set 312 | * 313 | ***************************************************************************************************/ 314 | if (false) { 315 | set s_s_src; 316 | set s_s; 317 | 318 | ret = client->sop_create("test:set_1", FLAG_STRING, 3); 319 | print(ret->get_result()); 320 | assert (ret->get_result() == true); 321 | 322 | for (i=0; i<6; i++) { 323 | char buff[256]; 324 | sprintf(buff, "item %d", i); 325 | s_s_src.insert(buff); 326 | } 327 | 328 | for (set::iterator it = s_s_src.begin(); 329 | it != s_s_src.end(); ++it) 330 | { 331 | ret = client->sop_insert("test:set_1", *it); 332 | print(ret->get_result()); 333 | assert (ret->get_result() == true); 334 | } 335 | 336 | ret = client->sop_get("test:set_1"); 337 | print(ret->get_result >()); 338 | assert (ret->get_result >() == s_s_src); 339 | 340 | for (set::iterator it = s_s_src.begin(); 341 | it != s_s_src.end(); ++it) 342 | { 343 | ret = client->sop_exist("test:set_1", *it); 344 | print(ret->get_result()); 345 | assert (ret->get_result() == true); 346 | } 347 | 348 | 349 | ret = client->sop_exist("test:set_1", "item 100"); 350 | print(ret->get_result()); 351 | assert (ret->get_result() == false); 352 | } 353 | 354 | 355 | 356 | /*************************************************************************************************** 357 | * 358 | * TEST 4: btree 359 | * 360 | ***************************************************************************************************/ 361 | if (false) { 362 | map > m_l_i; 363 | map, arcusBopItem > m_v_s; 364 | 365 | // int key 366 | ret = client->bop_create("test:btree_int", FLAG_INTEGER, 3); 367 | print (ret->get_result()); 368 | assert (ret->get_result() == true); 369 | 370 | 371 | 372 | for (i=0; i<1000; i++) { 373 | ret = client->bop_insert("test:btree_int", i, i, i); 374 | print(ret->get_result()); 375 | assert (ret->get_result() == true); 376 | } 377 | 378 | ret = client->bop_get("test:btree_int", 200, 400); 379 | m_l_i = ret->get_result_map(); // It's also possible 380 | // m_l_i = ret->get_result > >(); // this is also possible, but above will be more convnient. 381 | print (m_l_i); 382 | 383 | for (i=200; i<400; i++) { 384 | assert (m_l_i[i].eflag_uint64() == i); 385 | assert (m_l_i[i].value == i); 386 | } 387 | 388 | ret = client->bop_count("test:btree_int", 100, 199); 389 | print(ret->get_result()); 390 | assert (ret->get_result() == 100); 391 | 392 | // hex key 393 | ret = client->bop_create("test:btree_hex", FLAG_STRING, 3); 394 | print (ret->get_result()); 395 | assert (ret->get_result() == true); 396 | 397 | for (i=0; i<100; i++) { 398 | ret = client->bop_insert("test:btree_hex", util.i2vec(i), 399 | string("bop item ") + lexical_cast(i), i); 400 | print(ret->get_result()); 401 | assert (ret->get_result() == true); 402 | } 403 | 404 | ret = client->bop_get("test:btree_hex", util.i2vec(10), util.i2vec(30)); 405 | m_v_s = ret->get_result_map, string>(); 406 | print_vmap(m_v_s); 407 | 408 | for (i=10; i<30; i++) { 409 | assert (m_v_s[util.i2vec(i)].eflag_uint64() == i); 410 | assert (m_v_s[util.i2vec(i)].value == string("bop item ") + lexical_cast(i)); 411 | } 412 | 413 | 414 | // eflag test 415 | 416 | ret = client->bop_create("test:btree_eflag", FLAG_INTEGER, 3); 417 | print (ret->get_result()); 418 | assert (ret->get_result() == true); 419 | 420 | for (i=0; i<1000; i++) { 421 | ret = client->bop_insert("test:btree_eflag", i, i, i); 422 | print(ret->get_result()); 423 | assert (ret->get_result() == true); 424 | } 425 | 426 | ret = client->bop_get("test:btree_eflag", 200, 400, (arcusEflag() & 0x00ff) == 0x0001); 427 | m_l_i = ret->get_result_map(); 428 | print(m_l_i); 429 | assert (m_l_i[257].eflag_hex_str() == "0x0000000000000101"); 430 | assert (m_l_i[257].value == 257); 431 | 432 | ret = client->bop_get("test:btree_eflag", 200, 400, (arcusEflag() & 0x00ff) > 0x0010); 433 | m_l_i = ret->get_result_map(); 434 | print(m_l_i); 435 | 436 | for (i=200; i<400; i++) { 437 | if ((i & 0x00ff) <= 0x0010) { 438 | if (m_l_i.find(i) != m_l_i.end()) { 439 | assert (false); 440 | } 441 | 442 | continue; 443 | } 444 | 445 | assert (m_l_i[i].eflag_uint64() == i); 446 | assert (m_l_i[i].value == i); 447 | } 448 | } 449 | 450 | 451 | /*************************************************************************************************** 452 | * 453 | * TEST 5: btree mget, smget 454 | * 455 | ***************************************************************************************************/ 456 | if (false) { 457 | multimap > mm_l_i; 458 | map > > mget_l_i; 459 | 460 | // int key 461 | ret = client->bop_create("test:btree_1", FLAG_INTEGER, 3); 462 | print (ret->get_result()); 463 | assert (ret->get_result() == true); 464 | 465 | for (i=0; i<1000; i++) { 466 | ret = client->bop_insert("test:btree_1", i, i, i); 467 | print(ret->get_result()); 468 | assert (ret->get_result() == true); 469 | } 470 | 471 | ret = client->bop_create("test:btree_2", FLAG_INTEGER, 3); 472 | print (ret->get_result()); 473 | assert (ret->get_result() == true); 474 | 475 | for (i=1000; i<2000; i++) { 476 | ret = client->bop_insert("test:btree_2", i, i, i); 477 | print(ret->get_result()); 478 | assert (ret->get_result() == true); 479 | } 480 | 481 | ret = client->bop_create("test:btree_3", FLAG_INTEGER, 3); 482 | print (ret->get_result()); 483 | assert (ret->get_result() == true); 484 | 485 | for (i=2000; i<3000; i++) { 486 | ret = client->bop_insert("test:btree_3", i, i, i); 487 | print(ret->get_result()); 488 | assert (ret->get_result() == true); 489 | } 490 | 491 | 492 | arcusFutureList rets; 493 | vector key_list; 494 | 495 | 496 | key_list.clear(); 497 | key_list.push_back("test:btree_1"); 498 | key_list.push_back("test:btree_2"); 499 | key_list.push_back("test:btree_3"); 500 | key_list.push_back("test:btree_4"); 501 | key_list.push_back("test:btree_5"); 502 | rets = client->bop_mget(key_list, 500, 2500); 503 | mget_l_i = rets->get_mget_result(); 504 | print(mget_l_i); 505 | print(rets->get_missed_keys()); 506 | assert(rets->get_missed_keys()[0] == "test:btree_4"); 507 | assert(rets->get_missed_keys()[1] == "test:btree_5"); 508 | 509 | 510 | 511 | key_list.clear(); 512 | key_list.push_back("test:btree_1"); 513 | key_list.push_back("test:btree_2"); 514 | key_list.push_back("test:btree_3"); 515 | key_list.push_back("test:btree_4"); 516 | key_list.push_back("test:btree_5"); 517 | rets = client->bop_smget(key_list, 500, 2500); 518 | mm_l_i = rets->get_smget_result(); 519 | print(mm_l_i); 520 | print(rets->get_missed_keys()); 521 | 522 | idx = 500; 523 | for (multimap >::iterator it = mm_l_i.begin(); 524 | it != mm_l_i.end(); ++it, idx++) 525 | { 526 | assert (it->first == idx); 527 | assert (it->second.value == idx); 528 | assert (it->second.eflag_uint64() == idx); 529 | } 530 | 531 | assert(rets->get_missed_keys()[0] == "test:btree_4"); 532 | assert(rets->get_missed_keys()[1] == "test:btree_5"); 533 | } 534 | 535 | 536 | 537 | /*************************************************************************************************** 538 | * 539 | * TEST 6: dynamic list 540 | * 541 | ***************************************************************************************************/ 542 | if (false) { 543 | list l_s_src; 544 | for (i=0; i<6; i++) { 545 | char buff[256]; 546 | sprintf(buff, "item %d", i); 547 | l_s_src.push_back(buff); 548 | } 549 | 550 | arcusList arcus_list = arcusList::create(client, "test:arcus_list", FLAG_STRING, 5, 3); 551 | assert (arcus_list.size() == 0); 552 | 553 | arcus_list.insert(arcus_list.begin(), l_s_src.begin(), l_s_src.end()); 554 | assert (arcus_list.size() == l_s_src.size()); 555 | 556 | arcusList::iterator it_1 = arcus_list.begin(); 557 | list::iterator it_2 = l_s_src.begin(); 558 | for (; it_1 != arcus_list.end(); ++it_1, ++it_2) { 559 | assert(*it_1 == *it_2); 560 | } 561 | } 562 | 563 | 564 | 565 | /*************************************************************************************************** 566 | * 567 | * TEST 7: dynamic set 568 | * 569 | ***************************************************************************************************/ 570 | if (false) { 571 | list l_s_src; 572 | for (i=0; i<6; i++) { 573 | char buff[256]; 574 | sprintf(buff, "item %d", i); 575 | l_s_src.push_back(buff); 576 | } 577 | 578 | arcusSet arcus_set = arcusSet::create(client, "test:arcus_set", FLAG_STRING, 5, 3); 579 | assert (arcus_set.size() == 0); 580 | 581 | arcus_set.insert(l_s_src.begin(), l_s_src.end()); 582 | assert (arcus_set.size() == l_s_src.size()); 583 | 584 | list::iterator it = l_s_src.begin(); 585 | for (; it != l_s_src.end(); ++it) { 586 | assert (arcus_set.find(*it) != arcus_set.end()); 587 | } 588 | 589 | assert (arcus_set.find("invalid item") == arcus_set.end()); 590 | 591 | arcusSet::iterator it_1 = arcus_set.begin(); 592 | for (; it_1 != arcus_set.end(); ++it_1) { 593 | print(*it_1); 594 | } 595 | } 596 | 597 | /*************************************************************************************************** 598 | * 599 | * TEST 8: dynamic map 600 | * 601 | ***************************************************************************************************/ 602 | if (false) { 603 | map > m_is_src, new_map; 604 | for (i=0; i<6; i++) { 605 | char buff[256]; 606 | sprintf(buff, "item %d", i); 607 | m_is_src[i] = arcusBopItem(buff); 608 | } 609 | 610 | arcusMap arcus_map = arcusMap::create(client, "test:arcus_map", FLAG_STRING, 5, 3); 611 | assert (arcus_map.size() == 0); 612 | 613 | arcus_map.insert(m_is_src.begin(), m_is_src.end()); 614 | assert (arcus_map.size() == m_is_src.size()); 615 | 616 | new_map.insert(arcus_map.begin(), arcus_map.end()); 617 | assert (arcus_map.size() == new_map.size()); 618 | 619 | 620 | map >::iterator it = m_is_src.begin(); 621 | for (; it != m_is_src.end(); ++it) { 622 | assert (arcus_map[it->first].value == it->second.value); 623 | } 624 | } 625 | 626 | print ("### test done ###"); 627 | 628 | client->disconnect(); 629 | } 630 | 631 | 632 | -------------------------------------------------------------------------------- /arcus_mc_node.h: -------------------------------------------------------------------------------- 1 | /* vim: set fdc=2 foldmethod=marker ts=4 tabstop=4 sw=4 : */ 2 | /* 3 | * arcus-cpp-client - Arcus cpp client drvier 4 | * Copyright 2014 NAVER Corp. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | #ifndef __DEF_ARCUS_MC_NODE__ 20 | #define __DEF_ARCUS_MC_NODE__ 21 | 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | // boost 37 | #include 38 | #include 39 | 40 | using namespace boost; 41 | 42 | #include "arcus.h" 43 | 44 | 45 | 46 | class arcusMCNode; 47 | class arcusMCWorker; 48 | 49 | template 50 | void process_request_helper(arcusMCNode* node, const char* req, int rlen); 51 | 52 | struct arcusSystem/*{{{*/ 53 | { 54 | static bool shutdown(bool f = false) 55 | { 56 | static bool flag = false; 57 | 58 | if (f == true) { 59 | flag = true; 60 | } 61 | 62 | return flag; 63 | } 64 | }; 65 | /*}}}*/ 66 | 67 | class threadClass/*{{{*/ 68 | { 69 | public: 70 | virtual void run() = 0; 71 | 72 | static void* entry_point(void* vp) 73 | { 74 | threadClass *tc = (threadClass*)vp; 75 | 76 | tc->run(); 77 | } 78 | 79 | void start() 80 | { 81 | tid = pthread_create(&thread, NULL, entry_point, this); 82 | } 83 | 84 | void join() 85 | { 86 | pthread_join(thread, NULL); 87 | } 88 | 89 | private: 90 | pthread_t thread; 91 | int tid; 92 | }; 93 | /*}}}*/ 94 | 95 | class arcusMCWorker : public threadClass/*{{{*/ 96 | { 97 | public: 98 | static arcusMCWorker* handle() 99 | { 100 | static arcusMCWorker* w = NULL; 101 | 102 | if (w == NULL) { 103 | w = new arcusMCWorker(); 104 | } 105 | 106 | return w; 107 | } 108 | 109 | virtual void run() 110 | { 111 | arcus_log("worker: start\n"); 112 | while(true) { 113 | arcusFuture op = q.pop(); 114 | if (arcusSystem::shutdown() == true) { 115 | return; 116 | } 117 | 118 | arcus_log("worker: get operation (%p)%s\n", op.get(), op->request); 119 | arcusMCNode* node = (arcusMCNode*)op->node; 120 | process_request_helper(node, op->request, op->rlen); 121 | } 122 | } 123 | 124 | public: 125 | arcusMCWorker() { } 126 | async_queue q; 127 | }; 128 | /*}}}*/ 129 | 130 | struct arcusMCConnection/*{{{*/ 131 | { 132 | arcusMCConnection() { } 133 | 134 | int connect(const string& addr_port) 135 | { 136 | int idx = addr_port.find_first_of(":"); 137 | string addr = addr_port.substr(0, idx); 138 | int port; 139 | try { 140 | port = lexical_cast(addr_port.substr(idx+1)); 141 | } 142 | catch (bad_lexical_cast) { 143 | arcus_log("invalid port: %s\n", addr_port.substr(idx+1).c_str()); 144 | return -1; 145 | } 146 | 147 | struct sockaddr_in server_addr; 148 | memset(&server_addr, 0, sizeof(server_addr)); 149 | server_addr.sin_family = AF_INET; 150 | server_addr.sin_port = htons(port); 151 | server_addr.sin_addr.s_addr = inet_addr(addr.c_str()); 152 | 153 | sock = socket(PF_INET, SOCK_STREAM, 0); 154 | int ret = ::connect(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); 155 | // TODO : error 156 | 157 | arcus_log("Connection: [%s:%d] sock: %d connect -> %d\n", addr.c_str(), port, sock, ret); 158 | } 159 | 160 | int disconnect() 161 | { 162 | close(sock); 163 | sock = 0; 164 | } 165 | 166 | bool disconnected() 167 | { 168 | return sock == 0; 169 | } 170 | 171 | int send_request(const char* request, int rlen) 172 | { 173 | int ret = write(sock, request, rlen); 174 | arcus_log("Connection: send(%d): %s -> %d\n", sock, request, ret); 175 | return ret; 176 | } 177 | 178 | int find(const char* target, int tlen) 179 | { 180 | int slen = buff_len; 181 | int i, j; 182 | 183 | for (i=0; i slen) 189 | break; 190 | 191 | } 192 | 193 | if (j == tlen) { 194 | return i; 195 | } 196 | } 197 | 198 | return -1; 199 | } 200 | 201 | bool hasline() 202 | { 203 | int idx = find("\r\n", 2); 204 | return idx >= 0; 205 | } 206 | 207 | string readline() 208 | { 209 | int idx = -1; 210 | while (true) { 211 | idx = find("\r\n", 2); 212 | if (idx >= 0) { 213 | break; 214 | } 215 | 216 | char tmp[4096]; 217 | int ret = read(sock, tmp, sizeof(tmp)); 218 | // TODO ret 0, -1 219 | 220 | memcpy(buffer + buff_len, tmp, ret); 221 | buff_len += ret; 222 | } 223 | 224 | char line[sizeof(buffer)]; 225 | memcpy(line, buffer, idx); 226 | line[idx] = 0; 227 | 228 | idx += 2; // \r\n 229 | memmove(buffer, buffer + idx, buff_len - idx); 230 | buff_len -= idx; 231 | 232 | arcus_log("Connection: readline: '%s'\n", line); 233 | return line; 234 | } 235 | 236 | int readdata(char* buff, int len) 237 | { 238 | int ret; 239 | int idx = -1; 240 | while (true) { 241 | idx = find("\r\n", 2); 242 | if (idx >= 0) { 243 | break; 244 | } 245 | 246 | char tmp[4096]; 247 | int ret = read(sock, tmp, sizeof(tmp)); 248 | // TODO ret 0, -1 249 | 250 | memcpy(buffer + buff_len, tmp, ret); 251 | buff_len += ret; 252 | } 253 | 254 | char line[sizeof(buffer)]; 255 | memcpy(line, buffer, idx); 256 | line[idx] = 0; 257 | ret = idx; 258 | 259 | idx += 2; // \r\n 260 | memmove(buffer, buffer + idx, buff_len - idx); 261 | buff_len -= idx; 262 | 263 | memcpy (buff, line, ret); 264 | buff[ret] = 0; 265 | 266 | arcus_log("Connection: readdata: '%s'\n", buff); 267 | return ret; 268 | } 269 | 270 | int recv(char* data, int rlen) 271 | { 272 | while (buff_len < rlen) { 273 | char tmp[4096]; 274 | int ret = read(sock, tmp, sizeof(tmp)); 275 | // TODO ret 0, -1 276 | 277 | memcpy(buffer + buff_len, tmp, ret); 278 | buff_len += ret; 279 | } 280 | 281 | memcpy (data, buffer, rlen); 282 | arcus_log("Connection: recv(%d): %s\n", rlen, data); 283 | 284 | memmove(buffer, buffer + rlen, buff_len - rlen); 285 | buff_len -= rlen; 286 | 287 | return rlen; 288 | } 289 | 290 | int sock; 291 | char buffer[1024*128]; 292 | int buff_len; 293 | }; 294 | /*}}}*/ 295 | 296 | 297 | typedef arcusValue (arcusMCNode::*member_fn)(); 298 | 299 | class arcusMCOperation : public arcusOperation/*{{{*/ 300 | { 301 | public: 302 | arcusMCOperation(arcusNode* n, const char* cmd, int cmdlen, member_fn cb) : arcusOperation(n, cmd, cmdlen) 303 | { 304 | callback = cb; 305 | } 306 | 307 | 308 | public: 309 | member_fn callback; 310 | }; 311 | /*}}}*/ 312 | 313 | class arcusMCNode : public arcusNode 314 | { 315 | public: 316 | arcusMCNode(const string& addr, const string&name, arcusTranscoder* tc) : arcusNode(addr, name)/*{{{*/ 317 | { 318 | transcoder = tc; 319 | pthread_mutex_init(&mutex, NULL); 320 | 321 | handle.connect(addr); 322 | } 323 | /*}}}*/ 324 | 325 | virtual ~arcusMCNode()/*{{{*/ 326 | { 327 | 328 | } 329 | /*}}}*/ 330 | 331 | // 332 | // commands 333 | ////////////////////// 334 | virtual arcusFuture set(const string& key, const arcusValue& value, int exptime=0)/*{{{*/ 335 | { 336 | return _set("set", key, value, exptime); 337 | } 338 | /*}}}*/ 339 | 340 | virtual arcusFuture get(const string& key)/*{{{*/ 341 | { 342 | return _get("get", key); 343 | } 344 | /*}}}*/ 345 | 346 | virtual arcusFuture gets(const string& key)/*{{{*/ 347 | { 348 | return _get("gets", key); 349 | } 350 | /*}}}*/ 351 | 352 | virtual arcusFuture incr(const string& key, int v= 1)/*{{{*/ 353 | { 354 | return _incr_decr("incr", key, v); 355 | } 356 | /*}}}*/ 357 | 358 | virtual arcusFuture decr(const string& key, int v= 1)/*{{{*/ 359 | { 360 | return _incr_decr("decr", key, v); 361 | } 362 | /*}}}*/ 363 | 364 | virtual arcusFuture del(const string& key)/*{{{*/ 365 | { 366 | char buff[MAX_CMD_LEN]; 367 | int bufflen; 368 | 369 | bufflen = snprintf(buff, sizeof(buff), "delete %s\r\n", key.c_str()); 370 | 371 | return add_op("delete", buff, bufflen, &arcusMCNode::cb_delete); 372 | } 373 | /*}}}*/ 374 | 375 | virtual arcusFuture add(const string& key, const arcusValue& v, int exptime=0)/*{{{*/ 376 | { 377 | return _set("add", key, v, exptime); 378 | } 379 | /*}}}*/ 380 | 381 | virtual arcusFuture append(const string& key, const string& v, int exptime=0)/*{{{*/ 382 | { 383 | return _set("append", key, v, exptime); 384 | } 385 | /*}}}*/ 386 | 387 | virtual arcusFuture prepend(const string& key, const string& v, int exptime=0)/*{{{*/ 388 | { 389 | return _set("prepend", key, v, exptime); 390 | } 391 | /*}}}*/ 392 | 393 | virtual arcusFuture replace(const string& key, const arcusValue& v, int exptime=0)/*{{{*/ 394 | { 395 | return _set("replace", key, v, exptime); 396 | } 397 | /*}}}*/ 398 | 399 | virtual arcusFuture cas(const string& key, const arcusValue& v, int cas_id, int exptime=0)/*{{{*/ 400 | { 401 | return _set("cas", key, v, exptime, cas_id); 402 | } 403 | /*}}}*/ 404 | 405 | virtual arcusFuture lop_create(const string& key, ARCUS_TYPE type,/*{{{*/ 406 | int exptime = 0, const arcusAttribute& attrs = default_attrs) 407 | { 408 | return _coll_create("lop create", key, type, exptime, attrs); 409 | } 410 | /*}}}*/ 411 | 412 | virtual arcusFuture lop_insert(const string& key, int index, const arcusValue& value, /*{{{*/ 413 | const arcusAttribute& attrs = default_attrs) 414 | { 415 | char buff[MAX_ELEMENT_SIZE + MAX_CMD_LEN]; 416 | int bufflen; 417 | 418 | arcusData ret = transcoder->encode(value); 419 | 420 | if (attrs.create) { 421 | bufflen = snprintf(buff, sizeof(buff), "lop insert %s %d %d create %d %d %d%s%s%s%s\r\n", 422 | key.c_str(), index, ret.value.size(), 423 | attrs.flags, attrs.exptime, attrs.max_count, 424 | attrs.get_ovfl_action(), attrs.readable?"":" unreadable", 425 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 426 | } 427 | else { 428 | bufflen = snprintf(buff, sizeof(buff), "lop insert %s %d %d%s%s\r\n", 429 | key.c_str(), index, ret.value.size(), 430 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 431 | } 432 | 433 | memcpy(buff + bufflen, &ret.value[0], ret.value.size()); 434 | bufflen += ret.value.size(); 435 | memcpy(buff + bufflen, "\r\n", 2); 436 | bufflen += 2; 437 | 438 | return add_op("lop insert", buff, bufflen, &arcusMCNode::cb_coll_set); 439 | } 440 | /*}}}*/ 441 | 442 | virtual arcusFuture lop_get(const string& key, int start = 0, int end = -1, const arcusAttribute& attrs = default_attrs)/*{{{*/ 443 | { 444 | char buff[MAX_CMD_LEN]; 445 | int bufflen; 446 | 447 | bufflen = snprintf(buff, sizeof(buff), "lop get %s %d..%d%s%s\r\n", 448 | key.c_str(), start, end, attrs.del?" delete":"", attrs.drop?" drop":""); 449 | 450 | return add_op("lop get", buff, bufflen, &arcusMCNode::cb_lop_get); 451 | } 452 | /*}}}*/ 453 | 454 | virtual arcusFuture lop_delete(const string& key, int start = 0, int end = -1, const arcusAttribute& attrs = default_attrs)/*{{{*/ 455 | { 456 | char buff[MAX_CMD_LEN]; 457 | int bufflen; 458 | 459 | bufflen = snprintf(buff, sizeof(buff), "lop delete %s %d..%d%s%s%s\r\n", 460 | key.c_str(), start, end, attrs.drop?" drop":"", 461 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 462 | 463 | return add_op("lop delete", buff, bufflen, &arcusMCNode::cb_delete); 464 | } 465 | /*}}}*/ 466 | 467 | virtual arcusFuture sop_create(const string& key, ARCUS_TYPE type,/*{{{*/ 468 | int exptime = 0, const arcusAttribute& attrs = default_attrs) 469 | { 470 | return _coll_create("sop create", key, type, exptime, attrs); 471 | } 472 | /*}}}*/ 473 | 474 | virtual arcusFuture sop_insert(const string& key, const arcusValue& value, /*{{{*/ 475 | const arcusAttribute& attrs = default_attrs) 476 | { 477 | char buff[MAX_ELEMENT_SIZE + MAX_CMD_LEN]; 478 | int bufflen; 479 | 480 | arcusData ret = transcoder->encode(value); 481 | 482 | if (attrs.create) { 483 | bufflen = snprintf(buff, sizeof(buff), "sop insert %s %d create %d %d %d%s%s%s%s\r\n", 484 | key.c_str(), ret.value.size(), 485 | attrs.flags, attrs.exptime, attrs.max_count, 486 | attrs.get_ovfl_action(), attrs.readable?"":" unreadable", 487 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 488 | } 489 | else { 490 | bufflen = snprintf(buff, sizeof(buff), "sop insert %s %d%s%s\r\n", 491 | key.c_str(), ret.value.size(), 492 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 493 | } 494 | 495 | memcpy(buff + bufflen, &ret.value[0], ret.value.size()); 496 | bufflen += ret.value.size(); 497 | memcpy(buff + bufflen, "\r\n", 2); 498 | bufflen += 2; 499 | 500 | return add_op("sop insert", buff, bufflen, &arcusMCNode::cb_coll_set); 501 | } 502 | /*}}}*/ 503 | 504 | virtual arcusFuture sop_get(const string& key, int count = 0, const arcusAttribute& attrs = default_attrs)/*{{{*/ 505 | { 506 | char buff[MAX_CMD_LEN]; 507 | int bufflen; 508 | 509 | bufflen = snprintf(buff, sizeof(buff), "sop get %s %d%s%s\r\n", 510 | key.c_str(), count, attrs.del?" delete":"", attrs.drop?" drop":""); 511 | 512 | return add_op("sop get", buff, bufflen, &arcusMCNode::cb_sop_get); 513 | } 514 | /*}}}*/ 515 | 516 | virtual arcusFuture sop_exist(const string& key, const arcusValue& value, const arcusAttribute& attrs = default_attrs)/*{{{*/ 517 | { 518 | char buff[MAX_ELEMENT_SIZE + MAX_CMD_LEN]; 519 | int bufflen; 520 | 521 | arcusData ret = transcoder->encode(value); 522 | 523 | bufflen = snprintf(buff, sizeof(buff), "sop exist %s %d%s\r\n", 524 | key.c_str(), ret.value.size(), attrs.pipe?" pipe":""); 525 | 526 | memcpy(buff + bufflen, &ret.value[0], ret.value.size()); 527 | bufflen += ret.value.size(); 528 | memcpy(buff + bufflen, "\r\n", 2); 529 | bufflen += 2; 530 | 531 | return add_op("sop exist", buff, bufflen, &arcusMCNode::cb_sop_exist); 532 | } 533 | /*}}}*/ 534 | 535 | virtual arcusFuture sop_delete(const string& key, const arcusValue& value, const arcusAttribute& attrs = default_attrs)/*{{{*/ 536 | { 537 | char buff[MAX_ELEMENT_SIZE + MAX_CMD_LEN]; 538 | int bufflen; 539 | 540 | arcusData ret = transcoder->encode(value); 541 | 542 | bufflen = snprintf(buff, sizeof(buff), "sop delete %s %d%s%s%s\r\n", key.c_str(), ret.value.size(), 543 | attrs.drop?" drop":"", attrs.del?" delete":"", attrs.pipe?" pipe":""); 544 | 545 | memcpy(buff + bufflen, &ret.value[0], ret.value.size()); 546 | bufflen += ret.value.size(); 547 | memcpy(buff + bufflen, "\r\n", 2); 548 | bufflen += 2; 549 | 550 | return add_op("sop delete", buff, bufflen, &arcusMCNode::cb_delete); 551 | } 552 | /*}}}*/ 553 | 554 | virtual arcusFuture bop_create(const string& key, ARCUS_TYPE type, int exptime=0, const arcusAttribute& attrs = default_attrs)/*{{{*/ 555 | { 556 | return _coll_create("bop create", key, type, exptime, attrs); 557 | } 558 | /*}}}*/ 559 | 560 | virtual arcusFuture bop_insert(const string& key, const arcusBKey& bkey, const arcusValue& value, const arcusEflag& eflag = eflag_none, const arcusAttribute& attrs = default_attrs)/*{{{*/ 561 | { 562 | return _bop_set("bop insert", key, bkey, value, eflag, attrs); 563 | }/*}}}*/ 564 | 565 | virtual arcusFuture bop_upsert(const string& key, const arcusBKey& bkey, const arcusValue& value, const arcusEflag& eflag = eflag_none, const arcusAttribute& attrs = default_attrs)/*{{{*/ 566 | { 567 | return _bop_set("bop upsert", key, bkey, value, eflag, attrs); 568 | } 569 | /*}}}*/ 570 | 571 | virtual arcusFuture bop_update(const string& key, const arcusBKey& bkey, const arcusValue& value, const arcusEflag& eflag = eflag_none, const arcusAttribute& attrs = default_attrs)/*{{{*/ 572 | { 573 | return _bop_set("bop update", key, bkey, value, eflag, attrs); 574 | } 575 | /*}}}*/ 576 | 577 | virtual arcusFuture bop_get(const string& key, const arcusBKey& start, const arcusBKey& end, const arcusEflag& filter = default_filter, const arcusAttribute& attrs = default_attrs)/*{{{*/ 578 | { 579 | char buff[MAX_CMD_LEN]; 580 | int bufflen; 581 | 582 | bufflen = snprintf(buff, sizeof(buff), "bop get %s %s..%s %s%s%s\r\n", 583 | key.c_str(), start.to_str().c_str(), end.to_str().c_str(), 584 | filter.to_str().c_str(), attrs.del?" delete":"", attrs.drop?" drop":""); 585 | 586 | return add_op("bop get", buff, bufflen, &arcusMCNode::cb_bop_get); 587 | } 588 | /*}}}*/ 589 | 590 | virtual arcusFuture bop_delete(const string& key, const arcusBKey& start, const arcusBKey& end, const arcusEflag& filter = default_filter, const arcusAttribute& attrs = default_attrs)/*{{{*/ 591 | { 592 | char buff[MAX_CMD_LEN]; 593 | int bufflen; 594 | 595 | bufflen = snprintf(buff, sizeof(buff), "bop delete %s %d..%d%s%s%s\r\n", 596 | key.c_str(), start.to_str().c_str(), end.to_str().c_str(), attrs.drop?" drop":"", 597 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 598 | 599 | return add_op("bop delete", buff, bufflen, &arcusMCNode::cb_delete); 600 | } 601 | /*}}}*/ 602 | 603 | virtual arcusFuture bop_count(const string& key, const arcusBKey& start, const arcusBKey& end, const arcusEflag& filter = default_filter)/*{{{*/ 604 | { 605 | char buff[MAX_CMD_LEN]; 606 | int bufflen; 607 | 608 | bufflen = snprintf(buff, sizeof(buff), "bop count %s %s..%s %s\r\n", 609 | key.c_str(), start.to_str().c_str(), end.to_str().c_str(), filter.to_str().c_str()); 610 | 611 | return add_op("bop get", buff, bufflen, &arcusMCNode::cb_bop_get); 612 | } 613 | /*}}}*/ 614 | 615 | virtual arcusFuture bop_mget(const vector& key_list, const arcusBKey& start, const arcusBKey& end, const arcusEflag& filter = default_filter, int offset = 0, int count = 50)/*{{{*/ 616 | { 617 | char buff[MAX_CMD_LEN]; 618 | int bufflen; 619 | 620 | string comma_sep_keys; 621 | 622 | for (int i=0; i 0 ? lexical_cast(offset).c_str() : "", 634 | lexical_cast(count).c_str()); 635 | 636 | memcpy(buff+ bufflen, comma_sep_keys.c_str(), comma_sep_keys.length()); 637 | bufflen += comma_sep_keys.length(); 638 | memcpy(buff+ bufflen, "\r\n", 2); 639 | bufflen += 2; 640 | 641 | return add_op("bop mget", buff, bufflen, &arcusMCNode::cb_bop_mget); 642 | } 643 | /*}}}*/ 644 | 645 | virtual arcusFuture bop_smget(const vector& key_list, const arcusBKey& start, const arcusBKey& end, const arcusEflag& filter = default_filter, int offset = 0, int count = 50)/*{{{*/ 646 | { 647 | char buff[MAX_CMD_LEN]; 648 | int bufflen; 649 | 650 | string comma_sep_keys; 651 | 652 | for (int i=0; i 0 ? lexical_cast(offset).c_str() : "", 664 | lexical_cast(count).c_str()); 665 | 666 | memcpy(buff+ bufflen, comma_sep_keys.c_str(), comma_sep_keys.length()); 667 | bufflen += comma_sep_keys.length(); 668 | memcpy(buff+ bufflen, "\r\n", 2); 669 | bufflen += 2; 670 | 671 | return add_op("bop smget", buff, bufflen, &arcusMCNode::cb_bop_smget); 672 | } 673 | /*}}}*/ 674 | 675 | // 676 | // operations 677 | ///////////////////////// 678 | virtual int disconnect()/*{{{*/ 679 | { 680 | handle.disconnect(); 681 | 682 | list::iterator it = ops.begin(); 683 | for (; it != ops.end(); ++it) { 684 | (*it)->set_invalid(); 685 | } 686 | 687 | ops.clear(); 688 | return 0; 689 | } 690 | /*}}}*/ 691 | 692 | virtual int disconnect_all()/*{{{*/ 693 | { 694 | arcusSystem::shutdown(true); 695 | disconnect(); 696 | 697 | arcusMCWorker::handle()->q.push(arcusFuture(new arcusOperation())); 698 | return 0; 699 | } 700 | /*}}}*/ 701 | 702 | void process_request(const char* req, int rlen)/*{{{*/ 703 | { 704 | handle.send_request(req, rlen); 705 | } 706 | /*}}}*/ 707 | 708 | arcusFuture add_op(const string& cmd, const char* full_cmd, int cmd_len, member_fn callback, bool noreply = false)/*{{{*/ 709 | { 710 | arcusFuture op(new arcusMCOperation(this, full_cmd, cmd_len, callback)); 711 | 712 | if (noreply) { 713 | arcusMCWorker::handle()->q.push(op); 714 | op->set_result(true); 715 | } 716 | else { 717 | pthread_mutex_lock(&mutex); 718 | arcusMCWorker::handle()->q.push(op); 719 | ops.push_back(op); 720 | pthread_mutex_unlock(&mutex); 721 | } 722 | 723 | return op; 724 | } 725 | /*}}}*/ 726 | 727 | void do_op()/*{{{*/ 728 | { 729 | pthread_mutex_lock(&mutex); 730 | if (ops.empty()) { 731 | assert (false); 732 | } 733 | 734 | arcusFuture ft = *ops.begin(); 735 | ops.pop_front(); 736 | pthread_mutex_unlock(&mutex); 737 | 738 | 739 | arcusMCOperation* op = (arcusMCOperation*)ft.get(); 740 | arcusValue ret = (this->*(op->callback))(); 741 | op->set_result(ret); 742 | 743 | while (handle.hasline()) { // remaining jobs 744 | pthread_mutex_lock(&mutex); 745 | ft = *ops.begin(); 746 | ops.pop_front(); 747 | pthread_mutex_unlock(&mutex); 748 | 749 | arcusMCOperation* op = (arcusMCOperation*)ft.get(); 750 | arcusValue ret = (this->*(op->callback))(); 751 | op->set_result(ret); 752 | } 753 | } 754 | /*}}}*/ 755 | 756 | int get_fileno()/*{{{*/ 757 | { 758 | return handle.sock; 759 | } 760 | /*}}}*/ 761 | 762 | private: 763 | // 764 | // command subfucntions 765 | ////////////////////////// 766 | arcusFuture _set(const string& cmd, const string& key, const arcusValue& value, int exptime, int cas_id=-1)/*{{{*/ 767 | { 768 | char _buff[4096]; 769 | char *buff = _buff; 770 | int bufflen = sizeof(_buff); 771 | 772 | arcusData ret = transcoder->encode(value); 773 | 774 | if (ret.value.size() + 256 > bufflen) { 775 | bufflen = ret.value.size() + MAX_CMD_LEN; 776 | buff= (char*)malloc(bufflen); 777 | } 778 | 779 | if (cas_id != -1) { 780 | bufflen = snprintf(buff, bufflen, "%s %s %d %d %d\r\n", 781 | cmd.c_str(), key.c_str(), ret.flags, exptime, ret.value.size()); 782 | } 783 | else { 784 | bufflen = snprintf(buff, bufflen, "%s %s %d %d %d %d\r\n", 785 | cmd.c_str(), key.c_str(), ret.flags, exptime, ret.value.size(), cas_id); 786 | } 787 | 788 | memcpy(buff+ bufflen, &ret.value[0], ret.value.size()); 789 | bufflen += ret.value.size(); 790 | memcpy(buff+ bufflen, "\r\n", 2); 791 | bufflen += 2; 792 | 793 | arcusFuture ft = add_op(cmd, buff, bufflen, &arcusMCNode::cb_set); 794 | 795 | if (buff!= _buff) { 796 | free(buff); 797 | } 798 | 799 | return ft; 800 | } 801 | /*}}}*/ 802 | 803 | arcusFuture _get(const string& cmd, const string& key)/*{{{*/ 804 | { 805 | char buff[MAX_CMD_LEN]; 806 | int bufflen; 807 | 808 | bufflen = snprintf(buff, sizeof(buff), "%s %s\r\n", cmd.c_str(), key.c_str()); 809 | 810 | arcusFuture ft; 811 | if (cmd == "gets") { 812 | ft = add_op(cmd, buff, bufflen, &arcusMCNode::cb_gets); 813 | } 814 | else { 815 | ft = add_op(cmd, buff, bufflen, &arcusMCNode::cb_get); 816 | } 817 | 818 | return ft; 819 | } 820 | /*}}}*/ 821 | 822 | arcusFuture _incr_decr(const string& cmd, const string& key, int value)/*{{{*/ 823 | { 824 | char buff[MAX_CMD_LEN]; 825 | int bufflen; 826 | 827 | bufflen = snprintf(buff, sizeof(buff), "%s %s %d\r\n", cmd.c_str(), key.c_str(), value); 828 | 829 | arcusFuture ft; 830 | ft = add_op(cmd, buff, bufflen, &arcusMCNode::cb_incr_decr); 831 | 832 | return ft; 833 | } 834 | /*}}}*/ 835 | 836 | arcusFuture _coll_create(const string& cmd, const string& key, ARCUS_TYPE type,/*{{{*/ 837 | int exptime = 0, const arcusAttribute& attrs = default_attrs) 838 | { 839 | char buff[MAX_CMD_LEN]; 840 | int bufflen; 841 | 842 | bufflen = snprintf(buff, sizeof(buff), "%s %s %d %d %d%s%s%s\r\n", 843 | cmd.c_str(), key.c_str(), type, exptime, attrs.max_count, 844 | attrs.get_ovfl_action(), attrs.readable?"":" unreadable", 845 | attrs.noreply?" noreply":""); 846 | 847 | return add_op(cmd, buff, bufflen, &arcusMCNode::cb_coll_create); 848 | } 849 | /*}}}*/ 850 | 851 | virtual arcusFuture _bop_set(const string& cmd, const string& key, const arcusBKey& bkey, const arcusValue& value, const arcusEflag& eflag, const arcusAttribute& attrs = default_attrs)/*{{{*/ 852 | { 853 | char buff[MAX_ELEMENT_SIZE + MAX_CMD_LEN]; 854 | int bufflen; 855 | 856 | arcusData ret = transcoder->encode(value); 857 | 858 | if (attrs.create) { 859 | bufflen = snprintf(buff, sizeof(buff), "%s %s %s %s %d create %d %d %d%s%s%s%s\r\n", 860 | cmd.c_str(), key.c_str(), bkey.to_str().c_str(), eflag.to_str().c_str(), ret.value.size(), 861 | attrs.flags, attrs.exptime, attrs.max_count, 862 | attrs.get_ovfl_action(), attrs.readable?"":" unreadable", 863 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 864 | } 865 | else { 866 | bufflen = snprintf(buff, sizeof(buff), "%s %s %s %s %d%s%s\r\n", 867 | cmd.c_str(), key.c_str(), bkey.to_str().c_str(), eflag.to_str().c_str(), ret.value.size(), 868 | attrs.noreply?" noreply":"", attrs.pipe?" pipe":""); 869 | } 870 | 871 | memcpy(buff + bufflen, &ret.value[0], ret.value.size()); 872 | bufflen += ret.value.size(); 873 | memcpy(buff + bufflen, "\r\n", 2); 874 | bufflen += 2; 875 | 876 | return add_op("bop insert", buff, bufflen, &arcusMCNode::cb_coll_set); 877 | } 878 | /*}}}*/ 879 | 880 | 881 | // 882 | // callbacks 883 | ///////////////////// 884 | arcusValue cb_set()/*{{{*/ 885 | { 886 | string line = handle.readline(); 887 | if (line == "STORED") { 888 | return true; 889 | } 890 | 891 | if (line == "NOT_FOUND") { 892 | return false; 893 | } 894 | 895 | return false; 896 | } 897 | /*}}}*/ 898 | 899 | arcusValue cb_incr_decr()/*{{{*/ 900 | { 901 | string line = handle.readline(); 902 | int ret = 0; 903 | 904 | try { 905 | ret = lexical_cast(line); 906 | } 907 | catch (bad_lexical_cast) { 908 | arcus_log("invalid recv: %s\n", line.c_str()); 909 | return ARCUS_TYPE_EXCEPTION; 910 | } 911 | 912 | return ret; 913 | } 914 | /*}}}*/ 915 | 916 | arcusValue cb_get()/*{{{*/ 917 | { 918 | string line = handle.readline(); 919 | if (line.substr(0, 5) != "VALUE") { 920 | return ARCUS_PROTOCOL_EXCEPTION; 921 | } 922 | 923 | int idx = 0; 924 | string resp = tok(line, idx); 925 | string rkey = tok(line, idx); 926 | ARCUS_TYPE flags; 927 | int rlen; 928 | 929 | try { 930 | flags = TO_TYPE(lexical_cast(tok(line, idx))); 931 | rlen = lexical_cast(tok(line, idx)); 932 | } 933 | catch (bad_lexical_cast) { 934 | arcus_log("invalid recv: %s\n", line.c_str()); 935 | return ARCUS_PROTOCOL_EXCEPTION; 936 | } 937 | 938 | return decode_value(flags, rlen); 939 | } 940 | /*}}}*/ 941 | 942 | arcusValue cb_gets()/*{{{*/ 943 | { 944 | string line = handle.readline(); 945 | if (line.substr(0, 5) != "VALUE") { 946 | return ARCUS_PROTOCOL_EXCEPTION; 947 | } 948 | 949 | int idx = 0; 950 | string resp = tok(line, idx); 951 | string rkey = tok(line, idx); 952 | ARCUS_TYPE flags; 953 | int rlen; 954 | int cas_id; 955 | 956 | try { 957 | flags = TO_TYPE(lexical_cast(tok(line, idx))); 958 | rlen = lexical_cast(tok(line, idx)); 959 | cas_id = lexical_cast(tok(line, idx)); 960 | } 961 | catch (bad_lexical_cast) { 962 | arcus_log("invalid recv: %s\n", line.c_str()); 963 | return ARCUS_PROTOCOL_EXCEPTION; 964 | } 965 | 966 | return decode_value(flags, rlen); 967 | } 968 | /*}}}*/ 969 | 970 | arcusValue cb_coll_create()/*{{{*/ 971 | { 972 | string line = handle.readline(); 973 | if (line == "CREATED") { 974 | return true; 975 | } 976 | 977 | if (line == "EXISTS") { 978 | return ARCUS_COLLECTION_EXISTS_EXCEPTION; 979 | } 980 | 981 | return false; 982 | } 983 | /*}}}*/ 984 | 985 | arcusValue cb_coll_set()/*{{{*/ 986 | { 987 | string line = handle.readline(); 988 | if (line.substr(0, 8) == "RESPONSE") { 989 | int idx = 0; 990 | string dummy = tok(line, idx); 991 | int count; 992 | 993 | try { 994 | count = lexical_cast(tok(line, idx)); 995 | } 996 | catch (bad_lexical_cast) { 997 | arcus_log("invalid recv: %s\n", line.c_str()); 998 | return ARCUS_PROTOCOL_EXCEPTION; 999 | } 1000 | 1001 | list *ret = new list(); 1002 | for (int i=0; ipush_back(line); 1005 | } 1006 | 1007 | handle.readline(); // read 'END' 1008 | 1009 | return ret; 1010 | } 1011 | 1012 | if (line == "STORED") { 1013 | return true; 1014 | } 1015 | 1016 | if (line == "NOT_FOUND") { 1017 | return false; 1018 | } 1019 | 1020 | if (line == "TYPE_MISMATCH") { 1021 | return ARCUS_COLLECTION_TYPE_EXCEPTION; 1022 | } 1023 | 1024 | if (line == "OVERFLOWED") { 1025 | return ARCUS_COLLECTION_OVERFLOW_EXCEPTION; 1026 | } 1027 | 1028 | if (line == "OUT_OF_RANGE") { 1029 | return ARCUS_COLLECTION_INDEX_EXCEPTION; 1030 | } 1031 | 1032 | return false; 1033 | } 1034 | /*}}}*/ 1035 | 1036 | arcusValue cb_delete()/*{{{*/ 1037 | { 1038 | string line = handle.readline(); 1039 | if (line.substr(0, 8) == "RESPONSE") { 1040 | int idx = 0; 1041 | string dummy = tok(line, idx); 1042 | int count; 1043 | 1044 | try { 1045 | count = lexical_cast(tok(line, idx)); 1046 | } 1047 | catch (bad_lexical_cast) { 1048 | arcus_log("invalid recv: %s\n", line.c_str()); 1049 | return ARCUS_PROTOCOL_EXCEPTION; 1050 | } 1051 | 1052 | list *ret = new list(); 1053 | for (int i=0; ipush_back(line); 1056 | } 1057 | 1058 | handle.readline(); // read 'END' 1059 | 1060 | return ret; 1061 | } 1062 | 1063 | if (line == "DELETED") { 1064 | return true; 1065 | } 1066 | 1067 | if (line == "NOT_FOUND") { 1068 | return true; 1069 | } 1070 | 1071 | if (line == "TYPE_MISMATCH") { 1072 | return ARCUS_COLLECTION_TYPE_EXCEPTION; 1073 | } 1074 | 1075 | if (line == "OVERFLOWED") { 1076 | return ARCUS_COLLECTION_OVERFLOW_EXCEPTION; 1077 | } 1078 | 1079 | if (line == "OUT_OF_RANGE") { 1080 | return ARCUS_COLLECTION_INDEX_EXCEPTION; 1081 | } 1082 | 1083 | return false; 1084 | } 1085 | /*}}}*/ 1086 | 1087 | arcusValue cb_sop_exist()/*{{{*/ 1088 | { 1089 | string line = handle.readline(); 1090 | if (line == "EXIST") { 1091 | return true; 1092 | } 1093 | 1094 | return false; 1095 | } 1096 | /*}}}*/ 1097 | 1098 | arcusValue cb_lop_get()/*{{{*/ 1099 | { 1100 | return cb_coll_get(COLL_LOP); 1101 | } 1102 | /*}}}*/ 1103 | 1104 | arcusValue cb_sop_get()/*{{{*/ 1105 | { 1106 | return cb_coll_get(COLL_SOP); 1107 | } 1108 | /*}}}*/ 1109 | 1110 | arcusValue cb_coll_get(COLLECTION_TYPE ctype)/*{{{*/ 1111 | { 1112 | arcusValue ret; 1113 | ret.cflags = ctype; 1114 | bool bop_alloc = false; 1115 | 1116 | while (true) { 1117 | string line = handle.readline(); 1118 | 1119 | // handle error, end 1120 | if (line.substr(0, 5) != "VALUE" and line.substr(0, 5) != "COUNT") {/*{{{*/ 1121 | if (line == "NOT_FOUND") { 1122 | return ARCUS_COLLECTION_NOT_FOUND_EXCEPTION; 1123 | } 1124 | 1125 | if (line == "TYPE_MISMATCH") { 1126 | return ARCUS_COLLECTION_TYPE_EXCEPTION; 1127 | } 1128 | 1129 | if (line == "UNREADABLE") { 1130 | return ARCUS_COLLECTION_UNREADABLE_EXCEPTION; 1131 | } 1132 | 1133 | if (line == "OUT_OF_RANGE" || line == "NOT_FOUND_ELEMENT") { 1134 | return ARCUS_COLLECTION_INDEX_EXCEPTION; 1135 | } 1136 | 1137 | if (line == "END") { 1138 | break; 1139 | } 1140 | 1141 | return ARCUS_PROTOCOL_EXCEPTION; 1142 | } 1143 | /*}}}*/ 1144 | 1145 | // parsing flags, count, alloc 1146 | int idx = 0;/*{{{*/ 1147 | ARCUS_TYPE flags = FLAG_STRING; 1148 | int count = 0; 1149 | if (line.substr(0, 5) == "VALUE") { 1150 | string dummy = tok(line, idx); 1151 | flags = TO_TYPE(lexical_cast(tok(line, idx))); 1152 | count = lexical_cast(tok(line, idx)); 1153 | 1154 | ret.flags = flags; 1155 | 1156 | switch (ctype) 1157 | { 1158 | case COLL_LOP: 1159 | switch(flags) 1160 | { 1161 | case FLAG_STRING: ret.u.l_s = new list(); break; 1162 | case FLAG_BOOLEAN: ret.u.l_b = new list(); break; 1163 | case FLAG_INTEGER: ret.u.l_i = new list(); break; 1164 | case FLAG_LONG: ret.u.l_ll = new list(); break; 1165 | case FLAG_DATE: ret.u.l_t = new list(); break; 1166 | case FLAG_BYTE: ret.u.l_c = new list(); break; 1167 | case FLAG_FLOAT: ret.u.l_f = new list(); break; 1168 | case FLAG_DOUBLE: ret.u.l_d = new list(); break; 1169 | case FLAG_BYTEARRAY: ret.u.l_array = new list >(); break; 1170 | } 1171 | break; 1172 | 1173 | case COLL_SOP: 1174 | switch(flags) 1175 | { 1176 | case FLAG_STRING: ret.u.s_s = new std::set(); break; 1177 | case FLAG_BOOLEAN: ret.u.s_b = new std::set(); break; 1178 | case FLAG_INTEGER: ret.u.s_i = new std::set(); break; 1179 | case FLAG_LONG: ret.u.s_ll = new std::set(); break; 1180 | case FLAG_DATE: ret.u.s_t = new std::set(); break; 1181 | case FLAG_BYTE: ret.u.s_c = new std::set(); break; 1182 | case FLAG_FLOAT: ret.u.s_f = new std::set(); break; 1183 | case FLAG_DOUBLE: ret.u.s_d = new std::set(); break; 1184 | case FLAG_BYTEARRAY: ret.u.s_array = new std::set >(); break; 1185 | } 1186 | break; 1187 | 1188 | default: 1189 | break; 1190 | } 1191 | } 1192 | /*}}}*/ 1193 | 1194 | // decoding values 1195 | for (int i=0; i(buff); 1207 | break; 1208 | } 1209 | 1210 | if (i > 10) { 1211 | return ARCUS_PROTOCOL_EXCEPTION; 1212 | } 1213 | } 1214 | 1215 | arcusValue value = transcoder->decode(flags, data, length); 1216 | 1217 | switch (ctype) 1218 | { 1219 | case COLL_LOP: 1220 | switch(flags) 1221 | { 1222 | case FLAG_STRING: ret.u.l_s->push_back(value.str); break; 1223 | case FLAG_BOOLEAN: ret.u.l_b->push_back(value.u.b); break; 1224 | case FLAG_INTEGER: ret.u.l_i->push_back(value.u.i); break; 1225 | case FLAG_LONG: ret.u.l_ll->push_back(value.u.ll); break; 1226 | case FLAG_DATE: ret.u.l_t->push_back(value.time); break; 1227 | case FLAG_BYTE: ret.u.l_c->push_back(value.u.c); break; 1228 | case FLAG_FLOAT: ret.u.l_f->push_back(value.u.f); break; 1229 | case FLAG_DOUBLE: ret.u.l_d->push_back(value.u.d); break; 1230 | case FLAG_BYTEARRAY: ret.u.l_array->push_back(value.vec); break; 1231 | } 1232 | break; 1233 | 1234 | case COLL_SOP: 1235 | switch(flags) 1236 | { 1237 | case FLAG_STRING: ret.u.s_s->insert(value.str); break; 1238 | case FLAG_BOOLEAN: ret.u.s_b->insert(value.u.b); break; 1239 | case FLAG_INTEGER: ret.u.s_i->insert(value.u.i); break; 1240 | case FLAG_LONG: ret.u.s_ll->insert(value.u.ll); break; 1241 | case FLAG_DATE: ret.u.s_t->insert(value.time); break; 1242 | case FLAG_BYTE: ret.u.s_c->insert(value.u.c); break; 1243 | case FLAG_FLOAT: ret.u.s_f->insert(value.u.f); break; 1244 | case FLAG_DOUBLE: ret.u.s_d->insert(value.u.d); break; 1245 | case FLAG_BYTEARRAY: ret.u.s_array->insert(value.vec); break; 1246 | } 1247 | break; 1248 | } 1249 | } 1250 | /*}}}*/ 1251 | } 1252 | 1253 | return ret; 1254 | } 1255 | /*}}}*/ 1256 | 1257 | arcusValue cb_bop_get()/*{{{*/ 1258 | { 1259 | arcusValue ret; 1260 | ret.cflags = COLL_BOP; 1261 | bool bop_alloc = false; 1262 | arcusBKey::ARCUS_BKEY_TYPE bkey_type = arcusBKey::BKEY_LONG; 1263 | 1264 | while (true) { 1265 | string line = handle.readline(); 1266 | 1267 | // handle error, end 1268 | if (line.substr(0, 5) != "VALUE" and line.substr(0, 5) != "COUNT") {/*{{{*/ 1269 | if (line == "NOT_FOUND") { 1270 | return ARCUS_COLLECTION_NOT_FOUND_EXCEPTION; 1271 | } 1272 | 1273 | if (line == "TYPE_MISMATCH") { 1274 | return ARCUS_COLLECTION_TYPE_EXCEPTION; 1275 | } 1276 | 1277 | if (line == "UNREADABLE") { 1278 | return ARCUS_COLLECTION_UNREADABLE_EXCEPTION; 1279 | } 1280 | 1281 | if (line == "OUT_OF_RANGE" || line == "NOT_FOUND_ELEMENT") { 1282 | return ARCUS_COLLECTION_INDEX_EXCEPTION; 1283 | } 1284 | 1285 | if (line == "END") { 1286 | break; 1287 | } 1288 | 1289 | return ARCUS_PROTOCOL_EXCEPTION; 1290 | } 1291 | /*}}}*/ 1292 | 1293 | // parsing flag, count 1294 | int idx = 0;/*{{{*/ 1295 | ARCUS_TYPE flags = FLAG_STRING; 1296 | int count = 0; 1297 | if (line.substr(0, 5) == "VALUE") { 1298 | string dummy = tok(line, idx); 1299 | flags = TO_TYPE(lexical_cast(tok(line, idx))); 1300 | count = lexical_cast(tok(line, idx)); 1301 | ret.flags = flags; 1302 | } 1303 | else if (line.substr(0, 5) == "COUNT") { 1304 | string dummy = tok(line, idx, "="); 1305 | count = lexical_cast(tok(line, idx)); 1306 | return count; 1307 | } 1308 | /*}}}*/ 1309 | 1310 | // decoding values 1311 | for (int i=0; i(cp); 1329 | data = cp + strlen(cp) + 1; 1330 | } 1331 | else { // eflag not exists 1332 | length = lexical_cast(eflag); 1333 | data = eflag + strlen(eflag) + 1; 1334 | eflag = (char*)""; 1335 | } 1336 | 1337 | // bop alloc 1338 | if (bop_alloc == false)/*{{{*/ 1339 | { 1340 | bop_alloc = true; 1341 | 1342 | if (bkey_type == arcusBKey::BKEY_LONG) { 1343 | switch(flags) 1344 | { 1345 | case FLAG_STRING: ret.u.m_l_s = new map >(); break; 1346 | case FLAG_BOOLEAN: ret.u.m_l_b = new map >(); break; 1347 | case FLAG_INTEGER: ret.u.m_l_i = new map >(); break; 1348 | case FLAG_LONG: ret.u.m_l_ll = new map >(); break; 1349 | case FLAG_DATE: ret.u.m_l_t = new map >(); break; 1350 | case FLAG_BYTE: ret.u.m_l_c = new map >(); break; 1351 | case FLAG_FLOAT: ret.u.m_l_f = new map >(); break; 1352 | case FLAG_DOUBLE: ret.u.m_l_d = new map >(); break; 1353 | case FLAG_BYTEARRAY: ret.u.m_l_array = new map > >(); break; 1354 | } 1355 | } 1356 | else { 1357 | switch(flags) 1358 | { 1359 | case FLAG_STRING: ret.u.m_v_s = new map, arcusBopItem >(); break; 1360 | case FLAG_BOOLEAN: ret.u.m_v_b = new map, arcusBopItem >(); break; 1361 | case FLAG_INTEGER: ret.u.m_v_i = new map, arcusBopItem >(); break; 1362 | case FLAG_LONG: ret.u.m_v_ll = new map, arcusBopItem >(); break; 1363 | case FLAG_DATE: ret.u.m_v_t = new map, arcusBopItem >(); break; 1364 | case FLAG_BYTE: ret.u.m_v_c = new map, arcusBopItem >(); break; 1365 | case FLAG_FLOAT: ret.u.m_v_f = new map, arcusBopItem >(); break; 1366 | case FLAG_DOUBLE: ret.u.m_v_d = new map, arcusBopItem >(); break; 1367 | case FLAG_BYTEARRAY: ret.u.m_v_array = new map, arcusBopItem > >(); break; 1368 | } 1369 | } 1370 | }/*}}}*/ 1371 | 1372 | 1373 | // push value 1374 | arcusValue v = transcoder->decode(flags, data, length); 1375 | 1376 | if (bkey_type == arcusBKey::BKEY_LONG) { 1377 | uint64_t key = lexical_cast(bkey); 1378 | 1379 | switch(flags) 1380 | { 1381 | case FLAG_STRING: (*(ret.u.m_l_s))[key] = arcusBopItem(v.str, util.hstr2vec(eflag)); break; 1382 | case FLAG_BOOLEAN: (*(ret.u.m_l_b))[key] = arcusBopItem(v.u.b, util.hstr2vec(eflag)); break; 1383 | case FLAG_INTEGER: (*(ret.u.m_l_i))[key] = arcusBopItem(v.u.i, util.hstr2vec(eflag)); break; 1384 | case FLAG_LONG: (*(ret.u.m_l_ll))[key] = arcusBopItem(v.u.ll, util.hstr2vec(eflag)); break; 1385 | case FLAG_DATE: (*(ret.u.m_l_t))[key] = arcusBopItem(v.time, util.hstr2vec(eflag)); break; 1386 | case FLAG_BYTE: (*(ret.u.m_l_c))[key] = arcusBopItem(v.u.c, util.hstr2vec(eflag)); break; 1387 | case FLAG_FLOAT: (*(ret.u.m_l_f))[key] = arcusBopItem(v.u.f, util.hstr2vec(eflag)); break; 1388 | case FLAG_DOUBLE: (*(ret.u.m_l_d))[key] = arcusBopItem(v.u.d, util.hstr2vec(eflag)); break; 1389 | case FLAG_BYTEARRAY: (*(ret.u.m_l_array))[key] = arcusBopItem >(v.vec, util.hstr2vec(eflag)); break; 1390 | } 1391 | } 1392 | else { 1393 | vector key = util.hstr2vec(bkey); 1394 | 1395 | switch(flags) 1396 | { 1397 | case FLAG_STRING: (*(ret.u.m_v_s))[key] = arcusBopItem(v.str, util.hstr2vec(eflag)); break; 1398 | case FLAG_BOOLEAN: (*(ret.u.m_v_b))[key] = arcusBopItem(v.u.b, util.hstr2vec(eflag)); break; 1399 | case FLAG_INTEGER: (*(ret.u.m_v_i))[key] = arcusBopItem(v.u.i, util.hstr2vec(eflag)); break; 1400 | case FLAG_LONG: (*(ret.u.m_v_ll))[key] = arcusBopItem(v.u.ll, util.hstr2vec(eflag)); break; 1401 | case FLAG_DATE: (*(ret.u.m_v_t))[key] = arcusBopItem(v.time, util.hstr2vec(eflag)); break; 1402 | case FLAG_BYTE: (*(ret.u.m_v_c))[key] = arcusBopItem(v.u.c, util.hstr2vec(eflag)); break; 1403 | case FLAG_FLOAT: (*(ret.u.m_v_f))[key] = arcusBopItem(v.u.f, util.hstr2vec(eflag)); break; 1404 | case FLAG_DOUBLE: (*(ret.u.m_v_d))[key] = arcusBopItem(v.u.d, util.hstr2vec(eflag)); break; 1405 | case FLAG_BYTEARRAY: (*(ret.u.m_v_array))[key] = arcusBopItem >(v.vec, util.hstr2vec(eflag)); break; 1406 | } 1407 | } 1408 | } 1409 | /*}}}*/ 1410 | } 1411 | 1412 | return ret; 1413 | } 1414 | /*}}}*/ 1415 | 1416 | arcusValue cb_bop_mget()/*{{{*/ 1417 | { 1418 | arcusValue ret; 1419 | ret.cflags = COLL_BOP; 1420 | bool bop_alloc = false; 1421 | arcusBKey::ARCUS_BKEY_TYPE bkey_type = arcusBKey::BKEY_LONG; 1422 | 1423 | while (true) { 1424 | int idx, count; 1425 | string line = handle.readline(); 1426 | 1427 | // handle error, end 1428 | idx = 0; 1429 | count = 0; 1430 | 1431 | // handle error, end 1432 | if (line.substr(0, 5) != "VALUE" and line.substr(0, 5) != "COUNT") { 1433 | // TODO: check return 1434 | return ret; 1435 | } 1436 | 1437 | // parsing flag, count 1438 | idx = 0;/*{{{*/ 1439 | count = 0; 1440 | string KEY; 1441 | ARCUS_TYPE flags = FLAG_STRING; 1442 | if (line.substr(0, 5) == "VALUE") { 1443 | string dummy = tok(line, idx); 1444 | KEY = tok(line, idx); 1445 | string status = tok(line, idx); 1446 | 1447 | if (status == "OK" || status == "TRIMMED") { 1448 | flags = TO_TYPE(lexical_cast(tok(line, idx))); 1449 | count = lexical_cast(tok(line, idx)); 1450 | } 1451 | else if (status == "NOT_FOUND") { 1452 | ret.missed_keys.push_back(KEY); 1453 | continue; 1454 | } 1455 | else { 1456 | continue; 1457 | 1458 | } 1459 | 1460 | ret.flags = flags; 1461 | } 1462 | /*}}}*/ 1463 | 1464 | // decoding values 1465 | for (int i=0; i(cp); 1484 | data = cp + strlen(cp) + 1; 1485 | } 1486 | else { // eflag not exists 1487 | length = lexical_cast(eflag); 1488 | data = eflag + strlen(eflag) + 1; 1489 | eflag = NULL; 1490 | } 1491 | 1492 | // bop alloc 1493 | if (bop_alloc == false)/*{{{*/ 1494 | { 1495 | bop_alloc = true; 1496 | 1497 | if (bkey_type == arcusBKey::BKEY_LONG) { 1498 | switch(flags) 1499 | { 1500 | case FLAG_STRING: ret.u.mget_l_s = new map > >(); break; 1501 | case FLAG_BOOLEAN: ret.u.mget_l_b = new map > >(); break; 1502 | case FLAG_INTEGER: ret.u.mget_l_i = new map > >(); break; 1503 | case FLAG_LONG: ret.u.mget_l_ll = new map > >(); break; 1504 | case FLAG_DATE: ret.u.mget_l_t = new map > >(); break; 1505 | case FLAG_BYTE: ret.u.mget_l_c = new map > >(); break; 1506 | case FLAG_FLOAT: ret.u.mget_l_f = new map > >(); break; 1507 | case FLAG_DOUBLE: ret.u.mget_l_d = new map > >(); break; 1508 | case FLAG_BYTEARRAY: ret.u.mget_l_array = new map > > >(); break; 1509 | } 1510 | } 1511 | else { 1512 | switch(flags) 1513 | { 1514 | case FLAG_STRING: ret.u.mget_v_s = new map, arcusBopItem > >(); break; 1515 | case FLAG_BOOLEAN: ret.u.mget_v_b = new map, arcusBopItem > >(); break; 1516 | case FLAG_INTEGER: ret.u.mget_v_i = new map, arcusBopItem > >(); break; 1517 | case FLAG_LONG: ret.u.mget_v_ll = new map, arcusBopItem > >(); break; 1518 | case FLAG_DATE: ret.u.mget_v_t = new map, arcusBopItem > >(); break; 1519 | case FLAG_BYTE: ret.u.mget_v_c = new map, arcusBopItem > >(); break; 1520 | case FLAG_FLOAT: ret.u.mget_v_f = new map, arcusBopItem > >(); break; 1521 | case FLAG_DOUBLE: ret.u.mget_v_d = new map, arcusBopItem > >(); break; 1522 | case FLAG_BYTEARRAY: ret.u.mget_v_array = new map, arcusBopItem > > >(); break; 1523 | } 1524 | } 1525 | }/*}}}*/ 1526 | 1527 | 1528 | // push value 1529 | arcusValue v = transcoder->decode(flags, data, length); 1530 | 1531 | if (bkey_type == arcusBKey::BKEY_LONG) { 1532 | uint64_t key = lexical_cast(bkey); 1533 | 1534 | switch(flags) 1535 | { 1536 | case FLAG_STRING: (*(ret.u.mget_l_s))[KEY][key] = arcusBopItem(v.str, util.hstr2vec(eflag)); break; 1537 | case FLAG_BOOLEAN: (*(ret.u.mget_l_b))[KEY][key] = arcusBopItem(v.u.b, util.hstr2vec(eflag)); break; 1538 | case FLAG_INTEGER: (*(ret.u.mget_l_i))[KEY][key] = arcusBopItem(v.u.i, util.hstr2vec(eflag)); break; 1539 | case FLAG_LONG: (*(ret.u.mget_l_ll))[KEY][key] = arcusBopItem(v.u.ll, util.hstr2vec(eflag)); break; 1540 | case FLAG_DATE: (*(ret.u.mget_l_t))[KEY][key] = arcusBopItem(v.time, util.hstr2vec(eflag)); break; 1541 | case FLAG_BYTE: (*(ret.u.mget_l_c))[KEY][key] = arcusBopItem(v.u.c, util.hstr2vec(eflag)); break; 1542 | case FLAG_FLOAT: (*(ret.u.mget_l_f))[KEY][key] = arcusBopItem(v.u.f, util.hstr2vec(eflag)); break; 1543 | case FLAG_DOUBLE: (*(ret.u.mget_l_d))[KEY][key] = arcusBopItem(v.u.d, util.hstr2vec(eflag)); break; 1544 | case FLAG_BYTEARRAY: (*(ret.u.mget_l_array))[KEY][key] = arcusBopItem >(v.vec, util.hstr2vec(eflag)); break; 1545 | } 1546 | } 1547 | else { 1548 | vector key = util.hstr2vec(bkey); 1549 | 1550 | switch(flags) 1551 | { 1552 | case FLAG_STRING: (*(ret.u.mget_v_s))[KEY][key] = arcusBopItem(v.str, util.hstr2vec(eflag)); break; 1553 | case FLAG_BOOLEAN: (*(ret.u.mget_v_b))[KEY][key] = arcusBopItem(v.u.b, util.hstr2vec(eflag)); break; 1554 | case FLAG_INTEGER: (*(ret.u.mget_v_i))[KEY][key] = arcusBopItem(v.u.i, util.hstr2vec(eflag)); break; 1555 | case FLAG_LONG: (*(ret.u.mget_v_ll))[KEY][key] = arcusBopItem(v.u.ll, util.hstr2vec(eflag)); break; 1556 | case FLAG_DATE: (*(ret.u.mget_v_t))[KEY][key] = arcusBopItem(v.time, util.hstr2vec(eflag)); break; 1557 | case FLAG_BYTE: (*(ret.u.mget_v_c))[KEY][key] = arcusBopItem(v.u.c, util.hstr2vec(eflag)); break; 1558 | case FLAG_FLOAT: (*(ret.u.mget_v_f))[KEY][key] = arcusBopItem(v.u.f, util.hstr2vec(eflag)); break; 1559 | case FLAG_DOUBLE: (*(ret.u.mget_v_d))[KEY][key] = arcusBopItem(v.u.d, util.hstr2vec(eflag)); break; 1560 | case FLAG_BYTEARRAY: (*(ret.u.mget_v_array))[KEY][key] = arcusBopItem >(v.vec, util.hstr2vec(eflag)); break; 1561 | } 1562 | } 1563 | } 1564 | /*}}}*/ 1565 | } 1566 | 1567 | return ret; 1568 | } 1569 | /*}}}*/ 1570 | 1571 | arcusValue cb_bop_smget()/*{{{*/ 1572 | { 1573 | arcusValue ret; 1574 | ret.cflags = COLL_BOP; 1575 | bool bop_alloc = false; 1576 | arcusBKey::ARCUS_BKEY_TYPE bkey_type = arcusBKey::BKEY_LONG; 1577 | 1578 | while (true) { 1579 | int idx, count; 1580 | string line = handle.readline(); 1581 | 1582 | // handle error, end 1583 | idx = 0; 1584 | count = 0; 1585 | if (line.substr(0, 11) == "MISSED_KEYS") { 1586 | string dummy = tok(line, idx); 1587 | count = lexical_cast(tok(line, idx)); 1588 | 1589 | for (int i=0; i(tok(line, idx)); 1610 | } 1611 | /*}}}*/ 1612 | 1613 | // decoding values 1614 | for (int i=0; i(strtok_r(NULL, " ", &saveptr))); 1624 | bkey = strtok_r(NULL, " ", &saveptr); 1625 | if (bkey[0] == '0' && bkey[1] == 'x') { 1626 | bkey_type = arcusBKey::BKEY_HEX; 1627 | } 1628 | 1629 | eflag = strtok_r(NULL, " ", &saveptr); 1630 | if (eflag[0] == '0' && eflag[1] == 'x') { // eflag exists 1631 | char *cp = strtok_r(NULL, " ", &saveptr); 1632 | length = lexical_cast(cp); 1633 | data = cp + strlen(cp) + 1; 1634 | } 1635 | else { // eflag not exists 1636 | length = lexical_cast(eflag); 1637 | data = eflag + strlen(eflag) + 1; 1638 | eflag = NULL; 1639 | } 1640 | 1641 | // bop alloc 1642 | if (bop_alloc == false)/*{{{*/ 1643 | { 1644 | bop_alloc = true; 1645 | 1646 | if (bkey_type == arcusBKey::BKEY_LONG) { 1647 | switch(flags) 1648 | { 1649 | case FLAG_STRING: ret.u.mm_l_s = new multimap >(); break; 1650 | case FLAG_BOOLEAN: ret.u.mm_l_b = new multimap >(); break; 1651 | case FLAG_INTEGER: ret.u.mm_l_i = new multimap >(); break; 1652 | case FLAG_LONG: ret.u.mm_l_ll = new multimap >(); break; 1653 | case FLAG_DATE: ret.u.mm_l_t = new multimap >(); break; 1654 | case FLAG_BYTE: ret.u.mm_l_c = new multimap >(); break; 1655 | case FLAG_FLOAT: ret.u.mm_l_f = new multimap >(); break; 1656 | case FLAG_DOUBLE: ret.u.mm_l_d = new multimap >(); break; 1657 | case FLAG_BYTEARRAY: ret.u.mm_l_array = new multimap > >(); break; 1658 | } 1659 | } 1660 | else { 1661 | switch(flags) 1662 | { 1663 | case FLAG_STRING: ret.u.mm_v_s = new multimap, arcusBopItem >(); break; 1664 | case FLAG_BOOLEAN: ret.u.mm_v_b = new multimap, arcusBopItem >(); break; 1665 | case FLAG_INTEGER: ret.u.mm_v_i = new multimap, arcusBopItem >(); break; 1666 | case FLAG_LONG: ret.u.mm_v_ll = new multimap, arcusBopItem >(); break; 1667 | case FLAG_DATE: ret.u.mm_v_t = new multimap, arcusBopItem >(); break; 1668 | case FLAG_BYTE: ret.u.mm_v_c = new multimap, arcusBopItem >(); break; 1669 | case FLAG_FLOAT: ret.u.mm_v_f = new multimap, arcusBopItem >(); break; 1670 | case FLAG_DOUBLE: ret.u.mm_v_d = new multimap, arcusBopItem >(); break; 1671 | case FLAG_BYTEARRAY: ret.u.mm_v_array = new multimap, arcusBopItem > >(); break; 1672 | } 1673 | } 1674 | }/*}}}*/ 1675 | 1676 | 1677 | // push value 1678 | arcusValue v = transcoder->decode(flags, data, length); 1679 | 1680 | if (bkey_type == arcusBKey::BKEY_LONG) { 1681 | uint64_t key = lexical_cast(bkey); 1682 | 1683 | switch(flags) 1684 | { 1685 | case FLAG_STRING: ret.u.mm_l_s->insert(pair >(key,arcusBopItem(v.str, util.hstr2vec(eflag), KEY))); break; 1686 | case FLAG_BOOLEAN: ret.u.mm_l_b->insert(pair >(key,arcusBopItem(v.u.b, util.hstr2vec(eflag), KEY))); break; 1687 | case FLAG_INTEGER: ret.u.mm_l_i->insert(pair >(key,arcusBopItem(v.u.i, util.hstr2vec(eflag), KEY))); break; 1688 | case FLAG_LONG: ret.u.mm_l_ll->insert(pair >(key,arcusBopItem(v.u.ll, util.hstr2vec(eflag), KEY))); break; 1689 | case FLAG_DATE: ret.u.mm_l_t->insert(pair >(key,arcusBopItem(v.time, util.hstr2vec(eflag), KEY))); break; 1690 | case FLAG_BYTE: ret.u.mm_l_c->insert(pair >(key,arcusBopItem(v.u.c, util.hstr2vec(eflag), KEY))); break; 1691 | case FLAG_FLOAT: ret.u.mm_l_f->insert(pair >(key,arcusBopItem(v.u.f, util.hstr2vec(eflag), KEY))); break; 1692 | case FLAG_DOUBLE: ret.u.mm_l_d->insert(pair >(key,arcusBopItem(v.u.d, util.hstr2vec(eflag), KEY))); break; 1693 | case FLAG_BYTEARRAY: ret.u.mm_l_array->insert(pair > >(key,arcusBopItem >(v.vec, util.hstr2vec(eflag), KEY))); break; 1694 | } 1695 | } 1696 | else { 1697 | vector key = util.hstr2vec(bkey); 1698 | 1699 | switch(flags) 1700 | { 1701 | case FLAG_STRING: ret.u.mm_v_s->insert(pair, arcusBopItem >(key,arcusBopItem(v.str, util.hstr2vec(eflag), KEY))); break; 1702 | case FLAG_BOOLEAN: ret.u.mm_v_b->insert(pair, arcusBopItem >(key,arcusBopItem(v.u.b, util.hstr2vec(eflag), KEY))); break; 1703 | case FLAG_INTEGER: ret.u.mm_v_i->insert(pair, arcusBopItem >(key,arcusBopItem(v.u.i, util.hstr2vec(eflag), KEY))); break; 1704 | case FLAG_LONG: ret.u.mm_v_ll->insert(pair, arcusBopItem >(key,arcusBopItem(v.u.ll, util.hstr2vec(eflag), KEY))); break; 1705 | case FLAG_DATE: ret.u.mm_v_t->insert(pair, arcusBopItem >(key,arcusBopItem(v.time, util.hstr2vec(eflag), KEY))); break; 1706 | case FLAG_BYTE: ret.u.mm_v_c->insert(pair, arcusBopItem >(key,arcusBopItem(v.u.c, util.hstr2vec(eflag), KEY))); break; 1707 | case FLAG_FLOAT: ret.u.mm_v_f->insert(pair, arcusBopItem >(key,arcusBopItem(v.u.f, util.hstr2vec(eflag), KEY))); break; 1708 | case FLAG_DOUBLE: ret.u.mm_v_d->insert(pair, arcusBopItem >(key,arcusBopItem(v.u.d, util.hstr2vec(eflag), KEY))); break; 1709 | case FLAG_BYTEARRAY: ret.u.mm_v_array->insert(pair, arcusBopItem > >(key,arcusBopItem >(v.vec, util.hstr2vec(eflag), KEY))); break; 1710 | } 1711 | } 1712 | } 1713 | /*}}}*/ 1714 | } 1715 | 1716 | return ret; 1717 | } 1718 | /*}}}*/ 1719 | 1720 | arcusValue decode_value(ARCUS_TYPE flags, int rlen)/*{{{*/ 1721 | { 1722 | char _buff[4096]; 1723 | char *buff = _buff; 1724 | 1725 | if (rlen > sizeof(_buff)) { 1726 | buff = (char*)malloc(rlen); 1727 | } 1728 | 1729 | rlen += 2; 1730 | int ret = handle.recv(buff, rlen); 1731 | 1732 | if (ret != rlen) { 1733 | if (buff != _buff) { 1734 | free(buff); 1735 | } 1736 | return ARCUS_PROTOCOL_EXCEPTION; 1737 | } 1738 | 1739 | if (handle.readline() != "END") { 1740 | if (buff != _buff) { 1741 | free(buff); 1742 | } 1743 | return ARCUS_PROTOCOL_EXCEPTION; 1744 | } 1745 | 1746 | buff[ret-2] = 0; // strip \r\n 1747 | arcusValue value = transcoder->decode(flags, buff, ret - 2); 1748 | if (buff != _buff) { 1749 | free(buff); 1750 | } 1751 | 1752 | return value; 1753 | } 1754 | /*}}}*/ 1755 | 1756 | string tok(const string& src, int& start, const string& match = " ")/*{{{*/ 1757 | { 1758 | int idx = src.find_first_of(match, start); 1759 | if (idx < start) { 1760 | idx = src.length(); 1761 | } 1762 | 1763 | int org_start = start; 1764 | start = idx + match.length(); 1765 | 1766 | return src.substr(org_start, idx-org_start); 1767 | } 1768 | /*}}}*/ 1769 | 1770 | 1771 | private: 1772 | list ops; 1773 | arcusMCConnection handle; 1774 | arcusTranscoder* transcoder; 1775 | 1776 | pthread_mutex_t mutex; 1777 | }; 1778 | 1779 | #define EPOLL_SIZE 1024 1780 | 1781 | class arcusMCPoll : public threadClass/*{{{*/ 1782 | { 1783 | public: 1784 | static arcusMCPoll* handle() 1785 | { 1786 | static arcusMCPoll* p = NULL; 1787 | 1788 | if (p == NULL) { 1789 | p = new arcusMCPoll(); 1790 | } 1791 | 1792 | return p; 1793 | } 1794 | 1795 | ~arcusMCPoll() 1796 | { 1797 | close(efd); 1798 | free(events); 1799 | } 1800 | 1801 | virtual void run() 1802 | { 1803 | arcus_log("Poll: start\n"); 1804 | while(true) { 1805 | 1806 | int ret = epoll_wait(efd, events, EPOLL_SIZE, 20000); 1807 | 1808 | if (arcusSystem::shutdown() == true) { 1809 | return; 1810 | } 1811 | 1812 | arcus_log("Poll: ret - %d\n", ret); 1813 | 1814 | for (int i=0; ido_op(); 1819 | } 1820 | 1821 | if (events[i].events & EPOLLHUP) { 1822 | arcus_log("Poll: hup fd:%d\n", events[i].data.fd); 1823 | epoll_ctl(efd, EPOLL_CTL_DEL, events[i].data.fd, events); 1824 | arcusMCNode* node = sock_node_map[events[i].data.fd]; 1825 | node->disconnect(); 1826 | sock_node_map.erase(events[i].data.fd); 1827 | } 1828 | } 1829 | } 1830 | } 1831 | 1832 | void register_node(arcusMCNode* node) 1833 | { 1834 | struct epoll_event ev; 1835 | 1836 | ev.events = EPOLLIN | EPOLLHUP; 1837 | ev.data.fd = node->get_fileno(); 1838 | 1839 | sock_node_map[ev.data.fd] = node; 1840 | 1841 | arcus_log("Poll: register fd:%d\n", ev.data.fd); 1842 | epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev); 1843 | } 1844 | 1845 | private: 1846 | arcusMCPoll() 1847 | { 1848 | efd = epoll_create(EPOLL_SIZE); 1849 | events = (struct epoll_event *)malloc(sizeof(struct epoll_event) * EPOLL_SIZE); 1850 | } 1851 | 1852 | map sock_node_map; 1853 | 1854 | int efd; 1855 | struct epoll_event *events; 1856 | }; 1857 | /*}}}*/ 1858 | 1859 | class arcusMCNodeAllocator : public arcusNodeAllocator/*{{{*/ 1860 | { 1861 | public: 1862 | arcusMCNodeAllocator(arcusTranscoder* tc) 1863 | { 1864 | transcoder = tc; 1865 | arcusMCWorker::handle()->start(); 1866 | arcusMCPoll::handle()->start(); 1867 | } 1868 | 1869 | virtual arcusNode* alloc(const string& addr, const string& name) 1870 | { 1871 | arcusMCNode* node = new arcusMCNode(addr, name, transcoder); 1872 | arcusMCPoll::handle()->register_node(node); 1873 | return node; 1874 | } 1875 | 1876 | private: 1877 | arcusTranscoder* transcoder; 1878 | }; 1879 | /*}}}*/ 1880 | 1881 | template 1882 | void process_request_helper(arcusMCNode* node, const char* req, int rlen) 1883 | { 1884 | node->process_request(req, rlen); 1885 | } 1886 | 1887 | 1888 | #endif 1889 | 1890 | 1891 | --------------------------------------------------------------------------------