11 /* Mongo (rather antisocially) tries to define this itself. */
16 #include <mongo/client/dbclient.h>
17 using namespace mongo
;
19 /* TBD: parameterize */
20 #define MAIN_TBL "repo.main"
22 /* TBD: ick! Need to make the parser/query stuff reentrant. */
23 static BSONObj cur_bo
;
26 dbl_to_str (double *foo
, char *optr
)
29 unsigned char *iptr
= (unsigned char *)foo
;
31 for (i
= 0; i
< sizeof(*foo
); ++i
) {
32 optr
+= sprintf(optr
,"%02x",*(iptr
++));
45 DBClientConnection client
;
47 char * DidPut (char * bucket
, char * key
, char * loc
,
49 void GotCopy (char * bucket
, char * key
, char * loc
);
50 char * HasCopy (char * bucket
, char * key
, char * loc
);
51 int SetValue (char * bucket
, char * key
, char * mkey
,
53 int GetValue (char * bucket
, char * key
, char * mkey
,
55 RepoQuery
* NewQuery (char * expr
);
56 auto_ptr
<DBClientCursor
> GetCursor (Query
&q
);
57 void Delete (char * bucket
, char * key
);
58 size_t GetSize (char * bucket
, char * key
);
61 void BucketList (void); /* just sample code, don't use */
66 DBClientCursor
* curs
;
69 RepoQuery (char *, RepoMeta
&);
83 sprintf(addr
,"%s:%u",db_host
,db_port
);
93 RepoMeta::~RepoMeta ()
103 auto_ptr
<DBClientCursor
>
104 RepoMeta::GetCursor (Query
&q
)
106 auto_ptr
<DBClientCursor
> curs
;
108 curs
= client
.query(MAIN_TBL
,q
);
110 cout
<< "reconnecting" << endl
;
112 client
.connect("localhost");
114 catch (ConnectException
&ce
) {
115 cout
<< "server down" << endl
;
118 curs
= client
.query(MAIN_TBL
,q
);
125 RepoMeta::DidPut (char * bucket
, char * key
, char * loc
, size_t size
)
128 struct timeval now_tv
;
130 auto_ptr
<DBClientCursor
> curs
;
132 char now_str
[sizeof(now
)*2+1];
134 /* TBD: disambiguate master/slave cases a better way */
135 extern char * master_host
;
137 gettimeofday(&now_tv
,NULL
);
138 now
= (double)now_tv
.tv_sec
+ (double)now_tv
.tv_usec
/ 1000000.0;
139 dbl_to_str(&now
,now_str
);
140 cout
<< "now_str = " << now_str
<< endl
;
142 q
= QUERY("bucket"<<bucket
<<"key"<<key
);
145 /* Nice functionality, but what an ugly syntax! */
147 client
.update(MAIN_TBL
,q
,
148 BSON("$addToSet"<<BSON("loc"<<loc
)));
151 client
.update(MAIN_TBL
,q
,
152 BSON("$set"<<BSON("loc"<<BSON_ARRAY(loc
))));
154 client
.update(MAIN_TBL
,q
,BSON("$set"<<BSON("date"<<now
)));
155 client
.update(MAIN_TBL
,q
,BSON("$set"<<BSON("etag"<<now_str
)));
158 bb
<< "bucket" << bucket
<< "key" << key
159 << "loc" << BSON_ARRAY(loc
) << "date" << now
160 << "etag" << now_str
<< "size" << (long long)size
;
161 client
.insert(MAIN_TBL
,bb
.obj());
164 return strdup(now_str
);
168 meta_did_put (char * bucket
, char * key
, char * loc
, size_t size
)
170 return it
->DidPut(bucket
,key
,loc
,size
);
174 RepoMeta::GotCopy (char * bucket
, char * key
, char * loc
)
177 auto_ptr
<DBClientCursor
> curs
;
180 q
= QUERY("bucket"<<bucket
<<"key"<<key
);
183 /* Nice functionality, but what an ugly syntax! */
184 client
.update(MAIN_TBL
,q
,BSON("$addToSet"<<BSON("loc"<<loc
)));
187 cerr
<< bucket
<< ":" << key
<< " not found in GotCopy!" << endl
;
192 meta_got_copy (char * bucket
, char * key
, char * loc
)
194 it
->GotCopy(bucket
,key
,loc
);
198 RepoMeta::HasCopy (char * bucket
, char * key
, char * loc
)
201 auto_ptr
<DBClientCursor
> curs
;
205 q
= QUERY("bucket"<<bucket
<<"key"<<key
<<"loc"<<loc
);
211 value
= curs
->next().getStringField("etag");
212 if (!value
|| !*value
) {
215 return strdup(value
);
219 meta_has_copy (char * bucket
, char * key
, char * loc
)
221 return it
->HasCopy(bucket
,key
,loc
);
225 RepoMeta::SetValue (char * bucket
, char * key
, char * mkey
, char * mvalue
)
227 Query q
= QUERY("bucket"<<bucket
<<"key"<<key
);
229 client
.update(MAIN_TBL
,q
,BSON("$set"<<BSON(mkey
<<mvalue
)),1);
230 // TBD: check for and propagate errors.
235 meta_set_value (char * bucket
, char * key
, char * mkey
, char * mvalue
)
237 return it
->SetValue(bucket
,key
,mkey
,mvalue
);
241 RepoMeta::GetValue (char * bucket
, char * key
, char * mkey
, char ** mvalue
)
243 auto_ptr
<DBClientCursor
> curs
;
248 q
= QUERY("bucket"<<bucket
<<"key"<<key
);
256 data
= bo
.getStringField(mkey
);
257 if (!data
|| !*data
) {
261 *mvalue
= strdup(data
);
266 meta_get_value (char * bucket
, char * key
, char * mkey
, char ** mvalue
)
268 return it
->GetValue(bucket
,key
,mkey
,mvalue
);
271 RepoQuery::RepoQuery (char *qstr
, RepoMeta
&p
) : parent(p
)
274 auto_ptr
<DBClientCursor
> tmp
;
278 q
= QUERY("bucket"<<qstr
+1);
286 * TBD: we should really convert our query into one of Mongo's,
287 * and let them do all the work. Handling the general case
288 * would be pretty messy, but we could handle specific cases
289 * pretty easily. For example, a very high percentage of
290 * queries are likely to be a single field/value comparison.
291 * For now just punt, but revisit later.
296 curs
= parent
.GetCursor(q
).release();
301 RepoQuery::~RepoQuery ()
303 cout
<< "in " << __func__
<< endl
;
318 meta_query_stop (void * qobj
)
320 delete (RepoQuery
*)qobj
;
324 query_getter (char *id
)
326 return (char *)cur_bo
.getStringField(id
);
330 RepoQuery::Next (void)
334 while (curs
->more()) {
338 if (eval(expr
,&query_getter
,NULL
) <= 0) {
342 if (bucket
) { free(bucket
); }
343 bucket
= strdup(bo
.getStringField("bucket"));
344 if (key
) { free(key
); }
345 key
= strdup(bo
.getStringField("key"));
354 RepoMeta::NewQuery (char *expr
)
356 return new RepoQuery(expr
,*this);
360 meta_query_new (char *expr
)
362 return it
->NewQuery(expr
);
366 meta_query_next (void * qobj
, char ** bucket
, char ** key
)
368 RepoQuery
* rq
= (RepoQuery
*)qobj
;
375 *bucket
= rq
->bucket
;
381 RepoMeta::BucketList (void)
384 * TBD: make this return values instead of producing output.
385 * This is just a code fragment showing how to get a list of buckets,
390 BSONObj dist
= BSON("distinct"<<"main"<<"key"<<"bucket");
391 if (client
.runCommand("repo",dist
,repl
)) {
392 cout
<< repl
.toString() << endl
;
393 BSONObj elem
= repl
.getField("values").embeddedObject();
394 for (int i
= 0; i
< elem
.nFields(); ++i
) {
395 cout
<< elem
[i
].str() << endl
;
401 RepoMeta::Delete (char * bucket
, char * key
)
403 Query q
= QUERY("bucket"<<bucket
<<"key"<<key
);
405 client
.remove(MAIN_TBL
,q
);
410 meta_delete (char * bucket
, char * key
)
412 it
->Delete(bucket
,key
);
416 RepoMeta::GetSize (char * bucket
, char * key
)
418 auto_ptr
<DBClientCursor
> curs
;
423 q
= QUERY("bucket"<<bucket
<<"key"<<key
);
431 return bo
.getField("size").numberLong();
436 meta_get_size (char * bucket
, char * key
)
438 return it
->GetSize(bucket
,key
);