1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 /* broken test - this added just to make it compile */
28 
29 #include <kapp/main.h>
30 #include <kapp/args.h>
31 #include <kfs/directory.h>
32 #include <kfs/pagefile.h>
33 #include <kfs/file.h>
34 #include <kfs/mmap.h>
35 #include <kdb/btree.h>
36 #include <klib/token.h>
37 #include <klib/log.h>
38 #include <klib/out.h>
39 #include <klib/debug.h>
40 #include <klib/rc.h>
41 #include <sysalloc.h>
42 
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 
47 #define USE_EXTERN_TEXT_CMP 0
48 
49 
50 typedef struct test_btree_stat test_btree_stat;
51 struct test_btree_stat
52 {
53     uint32_t type;
54     uint32_t first_seen;
55     uint32_t count;
56 };
57 
58 static
test_btree_stat_report(const void * key,size_t key_size,KBTreeValue * val,void * ignore)59 void test_btree_stat_report ( const void *key, size_t key_size, KBTreeValue *val, void *ignore )
60 {
61     size_t bytes;
62     const test_btree_stat *stat;
63     rc_t rc = KBTreeValueAccessRead ( val, ( const void** ) & stat, & bytes );
64     if ( rc != 0 )
65         LOGERR ( klogInt, rc, "KBTreeValueAccessRead failed" );
66     else if ( bytes != sizeof * stat )
67         LOGMSG ( klogInt, "KBTreeValueAccessRead returned wrong size" );
68     else
69     {
70         printf ( "key: '%.*s'\n", ( int ) key_size, ( const char* ) key );
71         printf ( "  type %u\n", stat -> type );
72         printf ( "  first seen on line %u\n", stat -> first_seen );
73         printf ( "  occurs %u times.\n\n", stat -> count );
74     }
75 }
76 
77 #if USE_EXTERN_TEXT_CMP
78 static
bt_text_cmp(const void * a,size_t asize,const void * b,size_t bsize)79 int bt_text_cmp ( const void *a, size_t asize, const void *b, size_t bsize )
80 {
81     if ( asize < bsize )
82         return -1;
83     if ( asize > bsize )
84         return 1;
85     return memcmp ( a, b, asize );
86 }
87 #else
88 #define bt_text_cmp NULL
89 #endif
90 
91 static
test_readonly1(const KDirectory * dir,const KFile * in)92 rc_t test_readonly1 ( const KDirectory *dir, const KFile *in )
93 {
94     const KFile *backing;
95     rc_t rc = KDirectoryOpenFileRead ( dir, & backing, "test-btree.out" );
96     if ( rc == 0 )
97     {
98         const KBTree *bt;
99         rc = KBTreeMakeRead ( & bt, backing, 256 * 1024 * 1024, bt_text_cmp );
100         if ( rc != 0 )
101             LOGERR ( klogInt, rc, "KBTreeMakeRead failed" );
102         else
103         {
104             rc = KBTreeForEach ( bt, false, test_btree_stat_report, NULL );
105             if ( rc != 0 )
106                 LOGERR ( klogInt, rc, "KBTreeForEach failed" );
107 
108             KBTreeRelease ( bt );
109         }
110 
111         KFileRelease ( backing );
112     }
113     return rc;
114 }
115 
116 static
test_readonly(const KDirectory * dir,const KFile * in)117 rc_t test_readonly ( const KDirectory *dir, const KFile *in )
118 {
119     rc_t rc;
120 
121     rc = test_readonly1 ( dir, in );
122 
123     return rc;
124 }
125 
126 static
make_text_entry(KBTree * bt,const char * key,size_t key_size,int id,uint32_t lineno)127 rc_t make_text_entry ( KBTree *bt, const char *key, size_t key_size, int id, uint32_t lineno )
128 {
129     static int entry = 0;
130 
131     KBTreeValue val;
132     bool was_inserted;
133     test_btree_stat *stat;
134     rc_t rc = KBTreeEntry ( bt, & val, & was_inserted, sizeof * stat, key, key_size );
135     ++ entry;
136     if ( rc != 0 )
137     {
138         LOGERR ( klogInt, rc, "KBTreeEntry failed" );
139         printf ( "failed on entry %d\n", entry );
140         fflush ( stdout );
141     }
142     else
143     {
144         size_t bytes;
145         rc = KBTreeValueAccessUpdate ( & val, ( void** ) & stat, & bytes );
146         if ( rc != 0 )
147             LOGERR ( klogInt, rc, "KBTreeValueAccessUpdate failed" );
148         else
149         {
150             if ( bytes != sizeof * stat )
151                 rc = -1;
152             else if ( was_inserted )
153             {
154                 stat -> type = id;
155                 stat -> first_seen = lineno;
156                 stat -> count = 1;
157             }
158             else
159             {
160                 ++ stat -> count;
161             }
162         }
163 
164         KBTreeValueWhack ( & val );
165     }
166     return rc;
167 }
168 
169 static
test_update1(KDirectory * dir,const KFile * in,const char * path)170 rc_t test_update1 ( KDirectory *dir, const KFile *in, const char *path )
171 {
172     KFile *out;
173     rc_t rc = KDirectoryCreateFile ( dir, & out, true, 0666, kcmInit, "test-btree.out" );
174     if ( rc == 0 )
175     {
176         size_t pgsize = KPageConstSize ();
177         size_t key_max = ( pgsize > 1024 ) ? 255 : ( pgsize - 8 - 24 ) / 2;
178 
179         KBTree *bt;
180         rc = KBTreeMakeUpdate ( & bt, out,
181             256 * 1024 * 1024, false, kbtOpaqueKey,
182             8, sizeof ( test_btree_stat ),
183             1, key_max,
184             sizeof ( test_btree_stat ), sizeof ( test_btree_stat ),
185             bt_text_cmp );
186         if ( rc != 0 )
187             LOGERR ( klogInt, rc, "KBTreeMakeUpdate failed" );
188         else
189         {
190             const KMMap *mm;
191             rc = KMMapMakeRead ( & mm, in );
192             if ( rc == 0 )
193             {
194                 const void *addr;
195                 rc = KMMapAddrRead ( mm, &addr );
196                 if ( rc == 0 )
197                 {
198                     size_t size;
199                     rc = KMMapSize ( mm, & size );
200                     if ( rc == 0 )
201                     {
202                         char buffer [ 1024 ];
203 
204                         /* have a memory mapped input file, and it's text
205                            ( er, at least that's the idea *. */
206                         KToken t;
207                         KTokenText ttxt;
208                         KTokenSource src;
209                         String sstr, pstr;
210 
211                         /* test also assumes ASCII - sorry */
212                         StringInitCString ( & pstr, path );
213                         StringInit ( & sstr, addr, size, ( uint32_t ) size );
214                         KTokenTextInit ( & ttxt, & sstr, & pstr );
215                         KTokenSourceInit ( & src, & ttxt );
216 
217                         /* okay, now parse the file */
218                         while ( KTokenizerNext ( kDefaultTokenizer, & src, & t ) -> id != eEndOfInput )
219                         {
220                             switch  ( t . id )
221                             {
222                             case eUntermString:
223                             case eString:
224                             case eUntermEscapedString:
225                             case eEscapedString:
226                                 rc = KTokenToString ( & t, buffer, sizeof buffer, & size );
227                                 if ( rc != 0 )
228                                     rc = 0;
229                                 else
230                                     rc = make_text_entry ( bt, buffer, size, t . id, t . lineno );
231                                 break;
232 
233                             case eIdent:
234                             case eName:
235                                 rc = make_text_entry ( bt, t . str . addr, t . str . size, t . id, t . lineno );
236                                 break;
237                             }
238                         }
239                     }
240                 }
241 
242                 KMMapRelease ( mm );
243             }
244 
245             KBTreeRelease ( bt );
246         }
247 
248         KFileRelease ( out );
249     }
250     return rc;
251 }
252 
253 static
test_update(KDirectory * dir,const KFile * in,const char * path)254 rc_t test_update ( KDirectory *dir, const KFile *in, const char *path )
255 {
256     rc_t rc;
257 
258     rc = test_update1 ( dir, in, path );
259 
260     return rc;
261 }
262 
KAppVersion(void)263 ver_t CC KAppVersion ( void )
264 {
265     return 0;
266 }
267 
268 
269 const char UsageDefaultName[] = "vdb-unlock";
270 
UsageSummary(const char * progname)271 rc_t CC UsageSummary ( const char *progname )
272 {
273     return KOutMsg ( "\n"
274                      "Usage:\n"
275                      "  %s [Options] <target>\n"
276                      "\n"
277                      "Summary:\n"
278                      "  test the btree.\n"
279                      , progname
280         );
281 }
282 
Usage(const Args * args)283 rc_t CC Usage ( const Args *args )
284 {
285     const char * progname = UsageDefaultName;
286     const char * fullpath = UsageDefaultName;
287     rc_t rc;
288 
289     if (args == NULL)
290         rc = RC (rcApp, rcArgv, rcAccessing, rcSelf, rcNull);
291     else
292         rc = ArgsProgram (args, &fullpath, &progname);
293     if (rc)
294         progname = fullpath = UsageDefaultName;
295 
296     UsageSummary (progname);
297 
298     KOutMsg ("Options:\n");
299 
300     HelpOptionsStandard ();
301 
302     HelpVersion (fullpath, KAppVersion());
303 
304     return rc;
305 }
KMain(int argc,char * argv[])306 rc_t CC KMain ( int argc, char *argv [] )
307 {
308     Args *args;
309     rc_t rc = ArgsMakeAndHandle ( & args, argc, argv, 0 );
310     if ( rc != 0 )
311         LogErr ( klogErr, rc, "failed to parse arguments" );
312     else
313     {
314         KDirectory *wd;
315 
316         const char *path = "test-btree.c";
317         if ( argc == 2 )
318             path = argv [ 1 ];
319 
320         rc = KDirectoryNativeDir ( & wd );
321         if ( rc == 0 )
322         {
323             const KFile *in;
324             rc = KDirectoryOpenFileRead ( wd, & in, path );
325             if ( rc == 0 )
326             {
327                 rc = test_update ( wd, in, path );
328                 if ( rc == 0 )
329                     rc = test_readonly ( wd, in );
330 
331                 KFileRelease ( in );
332             }
333 
334             KDirectoryRelease ( wd );
335         }
336     }
337     return rc;
338 }
339