Switch to unified view

a/src/utils/circache.cpp b/src/utils/circache.cpp
1
/*
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the
14
 *   Free Software Foundation, Inc.,
15
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
 */
1
#ifndef lint
17
#ifndef lint
2
static char rcsid[] = "@(#$Id: $ (C) 2009 J.F.Dockes";
18
static char rcsid[] = "@(#$Id: $ (C) 2009 J.F.Dockes";
3
#endif
19
#endif
4
20
5
#ifndef TEST_CIRCACHE
21
#ifndef TEST_CIRCACHE
...
...
15
#include <sstream>
31
#include <sstream>
16
#include <iostream>
32
#include <iostream>
17
33
18
#include "circache.h"
34
#include "circache.h"
19
#include "conftree.h"
35
#include "conftree.h"
36
#include "debuglog.h"
20
37
21
using namespace std;
38
using namespace std;
22
39
23
/*
40
/*
24
 * File structure:
41
 * File structure:
25
 * - Starts with a 1-KB header block, with a param dictionary, ascii-space 
42
 * - Starts with a 1-KB header block, with a param dictionary.
26
 *   filled. 
27
 * - Stored items follow. Each item has 2 segments for the metadata and the 
43
 * - Stored items follow. Each item has a header and 2 segments for
44
 *   the metadata and the data. 
28
 *   data. The segment sizes are stored in an ascii header/marker.
45
 *   The segment sizes are stored in the ascii header/marker:
29
 *     circacheSizes = xxx yyy zzz
46
 *     circacheSizes = xxx yyy zzz
30
 *     xxx bytes of metadata
47
 *     xxx bytes of metadata
31
 *     yyy bytes of data
48
 *     yyy bytes of data
32
 *     zzz bytes of padding up to next object
49
 *     zzz bytes of padding up to next object (only one entry has non zero)
33
 *
50
 *
34
 * There is a write position, which can be at eof while 
51
 * There is a write position, which can be at eof while 
35
 * the file is growing, or inside the file if we are recycling. This is stored
52
 * the file is growing, or inside the file if we are recycling. This is stored
36
 * in the header, together with the maximum size
53
 * in the header, together with the maximum size
37
 *
54
 *
38
 * If we are recycling, we have to take care to compute the size of the 
55
 * If we are recycling, we have to take care to compute the size of the 
39
 * possible remaining area from the last object invalidated by the write, 
56
 * possible remaining area from the last object invalidated by the write, 
40
 * pad it with neutral data and store the size in the new header.
57
 * pad it with neutral data and store the size in the new header.
41
 */
58
 */
42
59
43
// First block in file. 
60
// First block size
44
#define CIRCACHE_FIRSTBLOCK_SIZE 1024
61
#define CIRCACHE_FIRSTBLOCK_SIZE 1024
45
62
46
// Entry header.
63
// Entry header.
47
// The 32 bits size are stored as hex integers so the maximum size is
64
// The 32 bits size are stored as hex integers so the maximum size is
48
// 13 + 3x8 + 6 = 43
65
// 13 + 3x8 + 6 = 43
...
...
109
    }
126
    }
110
127
111
    // Name for the cache file
128
    // Name for the cache file
112
    string datafn(const string& d)
129
    string datafn(const string& d)
113
    {
130
    {
114
        return  path_cat(d, "circache");
131
        return  path_cat(d, "circache.crch");
115
    }
132
    }
116
133
117
    bool writefirstblock()
134
    bool writefirstblock()
118
    {
135
    {
119
        assert(m_fd >= 0);
136
        assert(m_fd >= 0);
...
...
226
            return false;
243
            return false;
227
        }
244
        }
228
        return true;
245
        return true;
229
    }
246
    }
230
247
231
    CCScanHook::status scan(off_t startoffset, CCScanHook *user)
248
    CCScanHook::status scan(off_t startoffset, CCScanHook *user, 
249
                            bool fold = false)
232
    {
250
    {
233
        assert(m_fd >= 0);
251
        assert(m_fd >= 0);
234
252
253
        off_t so0 = startoffset;
254
        bool already_folded = false;
255
        
235
        while (true) {
256
        while (true) {
257
            if (already_folded && startoffset == so0)
258
                return CCScanHook::Eof;
259
236
            EntryHeaderData d;
260
            EntryHeaderData d;
237
            CCScanHook::status st;
261
            CCScanHook::status st;
238
            if ((st = readentryheader(startoffset, d)) != 
262
            switch ((st = readentryheader(startoffset, d))) {
239
                CCScanHook::Continue) {
263
            case CCScanHook::Continue: break;
264
            case CCScanHook::Eof:
265
                if (fold && !already_folded) {
266
                    already_folded = true;
267
                    startoffset = CIRCACHE_FIRSTBLOCK_SIZE;
268
                    continue;
269
                }
270
                /* FALLTHROUGH */
271
            default:
240
                return st;
272
                return st;
241
            }
273
            }
274
242
            char *bf;
275
            char *bf;
243
            if ((bf = buf(d.dicsize+1)) == 0) {
276
            if ((bf = buf(d.dicsize+1)) == 0) {
244
                return CCScanHook::Error;
277
                return CCScanHook::Error;
245
            }
278
            }
246
            bf[d.dicsize] = 0;
279
            bf[d.dicsize] = 0;
...
...
294
{
327
{
295
    assert(m_d != 0);
328
    assert(m_d != 0);
296
    struct stat st;
329
    struct stat st;
297
    if (stat(m_dir.c_str(), &st) < 0) {
330
    if (stat(m_dir.c_str(), &st) < 0) {
298
        if (mkdir(m_dir.c_str(), 0777) < 0) {
331
        if (mkdir(m_dir.c_str(), 0777) < 0) {
299
            m_d->m_reason << "CirCache::create: mkdir(" << m_dir << ") failed" <<
332
            m_d->m_reason << "CirCache::create: mkdir(" << m_dir << 
300
                " errno " << errno;
333
                ") failed" << " errno " << errno;
301
            return false;
334
            return false;
302
        }
335
        }
303
    }
336
    }
304
337
305
    if ((m_d->m_fd = ::open(m_d->datafn(m_dir).c_str(), 
338
    if ((m_d->m_fd = ::open(m_d->datafn(m_dir).c_str(), 
...
...
315
348
316
    char buf[CIRCACHE_FIRSTBLOCK_SIZE];
349
    char buf[CIRCACHE_FIRSTBLOCK_SIZE];
317
    memset(buf, 0, CIRCACHE_FIRSTBLOCK_SIZE);
350
    memset(buf, 0, CIRCACHE_FIRSTBLOCK_SIZE);
318
    if (::write(m_d->m_fd, buf, CIRCACHE_FIRSTBLOCK_SIZE) != 
351
    if (::write(m_d->m_fd, buf, CIRCACHE_FIRSTBLOCK_SIZE) != 
319
        CIRCACHE_FIRSTBLOCK_SIZE) {
352
        CIRCACHE_FIRSTBLOCK_SIZE) {
320
        m_d->m_reason << "CirCache::create: write header failed, errno " << errno;
353
        m_d->m_reason << "CirCache::create: write header failed, errno " 
354
                      << errno;
321
        return false;
355
        return false;
322
    }
356
    }
323
    return m_d->writefirstblock();
357
    return m_d->writefirstblock();
358
}
359
360
bool CirCache::open(OpMode mode)
361
{
362
    assert(m_d != 0);
363
    if (m_d->m_fd >= 0)
364
        ::close(m_d->m_fd);
365
366
    if ((m_d->m_fd = ::open(m_d->datafn(m_dir).c_str(), 
367
                          mode == CC_OPREAD ? O_RDONLY : O_RDWR)) < 0) {
368
        m_d->m_reason << "CirCache::open: open(" << m_d->datafn(m_dir) << 
369
            ") failed " << "errno " << errno;
370
        return false;
371
    }
372
    return m_d->readfirstblock();
324
}
373
}
325
374
326
class CCScanHookDump : public  CCScanHook {
375
class CCScanHookDump : public  CCScanHook {
327
public:
376
public:
328
    virtual status takeone(off_t offs, const string& udi, unsigned int dicsize, 
377
    virtual status takeone(off_t offs, const string& udi, unsigned int dicsize, 
329
                           unsigned int datasize, unsigned int padsize) 
378
                           unsigned int datasize, unsigned int padsize) 
330
    {
379
    {
331
        cout << "udi [" << udi << "] dicsize " << dicsize << " datasize "
380
        cout << "Scan: offs " << offs << " dicsize " << dicsize 
332
             << datasize << " padsize " << padsize << endl;
381
             << " datasize " << datasize << " padsize " << padsize << 
382
            " udi [" << udi << "]" << endl;
333
        return Continue;
383
        return Continue;
334
    }
384
    }
335
};
385
};
336
386
337
bool CirCache::open(OpMode mode)
387
bool CirCache::dump()
388
{
389
    CCScanHookDump dumper;
390
    off_t start = m_d->m_nheadoffs > CIRCACHE_FIRSTBLOCK_SIZE ? 
391
        m_d->m_nheadoffs : CIRCACHE_FIRSTBLOCK_SIZE;
392
    switch (m_d->scan(start, &dumper, true)) {
393
    case CCScanHook::Stop: 
394
        cout << "Scan returns Stop??" << endl;
395
        return false;
396
    case CCScanHook::Continue: 
397
        cout << "Scan returns Continue ?? " << CCScanHook::Continue << " " <<
398
            getReason() << endl;
399
        return false;
400
    case CCScanHook::Error: 
401
        cout << "Scan returns Error: " << getReason() << endl;
402
        return false;
403
    case CCScanHook::Eof:
404
        cout << "Scan returns Eof" << endl;
405
        return true;
406
    default:
407
        cout << "Scan returns Unknown ??" << endl;
408
        return false;
409
    }
410
}
411
412
class CCScanHookGetter : public  CCScanHook {
413
public:
414
    string  m_udi;
415
    int     m_targinstance;
416
    int     m_instance;
417
    off_t   m_offs;
418
    EntryHeaderData m_hd;
419
420
    CCScanHookGetter(const string &udi, int ti)
421
        : m_udi(udi), m_targinstance(ti), m_instance(0), m_offs(0){}
422
423
    virtual status takeone(off_t offs, const string& udi, unsigned int dicsize, 
424
                           unsigned int datasize, unsigned int padsize) 
425
    {
426
        cerr << "offs " << offs << " udi [" << udi << "] dicsize " << dicsize 
427
             << " datasize " << datasize << " padsize " << padsize << endl;
428
        if (!m_udi.compare(udi)) {
429
            m_instance++;
430
            m_offs = offs;
431
            m_hd.dicsize = dicsize;
432
            m_hd.datasize = datasize;
433
            m_hd.padsize = padsize;
434
            if (m_instance == m_targinstance)
435
                return Stop;
436
        }
437
        return Continue;
438
    }
439
};
440
441
// instance == -1 means get latest. Otherwise specify from 1+
442
bool CirCache::get(const string& udi, string& dict, string& data, int instance)
338
{
443
{
339
    assert(m_d != 0);
444
    assert(m_d != 0);
340
    if (m_d->m_fd >= 0)
445
    if (m_d->m_fd < 0) {
341
        ::close(m_d->m_fd);
446
        m_d->m_reason << "CirCache::get: not open";
447
        return false;
448
    }
342
449
343
    if ((m_d->m_fd = ::open(m_d->datafn(m_dir).c_str(), 
450
    LOGDEB(("CirCache::get: udi [%s], instance\n", udi.c_str(), instance));
344
                          mode == CC_OPREAD ? O_RDONLY : O_RDWR)) < 0) {
451
345
        m_d->m_reason << "CirCache::open: open(" << m_d->datafn(m_dir) << 
452
    CCScanHookGetter getter(udi, instance);
346
            ") failed " << "errno " << errno;
453
    off_t start = m_d->m_nheadoffs > CIRCACHE_FIRSTBLOCK_SIZE ? 
454
        m_d->m_nheadoffs : CIRCACHE_FIRSTBLOCK_SIZE;
455
456
    CCScanHook::status ret = m_d->scan(start, &getter, true);
457
    if (ret == CCScanHook::Eof) {
458
        if (getter.m_instance == 0)
347
        return false;
459
            return false;
460
    } else if (ret != CCScanHook::Stop) {
461
        return false;
348
    }
462
    }
349
    bool ret = m_d->readfirstblock();
463
    off_t offs = getter.m_offs + CIRCACHE_HEADER_SIZE;
350
464
    if (lseek(m_d->m_fd, offs, 0) != offs) {
351
    if (mode == CC_OPREAD) {
465
        m_d->m_reason << "CirCache::get: lseek(" << offs << ") failed: " << 
352
        CCScanHookDump dumper;
353
        switch (m_d->scan(CIRCACHE_FIRSTBLOCK_SIZE, &dumper)) {
354
        case CCScanHook::Stop: 
355
            cerr << "Scan returns Stop" << endl;
356
            break;
466
            errno;
357
        case CCScanHook::Continue: 
467
        return false;
358
            cerr << "Scan returns Continue ?? " << CCScanHook::Continue << " " <<
359
                getReason() << endl;
360
            break;
361
        case CCScanHook::Error: 
362
            cerr << "Scan returns Error: " << getReason() << endl;
363
            break;
364
        case CCScanHook::Eof:
365
            cerr << "Scan returns Eof" << endl;
366
            break;
367
        }
468
    }
469
    char *bf = m_d->buf(getter.m_hd.dicsize);
470
    if (bf == 0)
471
        return false;
472
    if (read(m_d->m_fd, bf, getter.m_hd.dicsize) != int(getter.m_hd.dicsize)) {
473
        m_d->m_reason << "CirCache::get: read() failed: errno " << errno;
474
        return false;
368
    }
475
    }
369
    return ret;
476
    dict.assign(bf, getter.m_hd.dicsize);
370
}
371
477
372
bool CirCache::get(const string& udi, string dic, string data)
478
    bf = m_d->buf(getter.m_hd.datasize);
373
{
479
    if (bf == 0)
480
        return false;
481
    if (read(m_d->m_fd, bf, getter.m_hd.datasize) != int(getter.m_hd.datasize)){
482
        m_d->m_reason << "CirCache::get: read() failed: errno " << errno;
483
        return false;
484
    }
485
    data.assign(bf, getter.m_hd.datasize);
486
374
    return true;
487
    return true;
375
}
488
}
376
489
377
class CCScanHookSpacer : public  CCScanHook {
490
class CCScanHookSpacer : public  CCScanHook {
378
public:
491
public:
...
...
383
        : sizewanted(sz), sizeseen(0) {assert(sz > 0);}
496
        : sizewanted(sz), sizeseen(0) {assert(sz > 0);}
384
497
385
    virtual status takeone(off_t offs, const string& udi, unsigned int dicsize, 
498
    virtual status takeone(off_t offs, const string& udi, unsigned int dicsize, 
386
                           unsigned int datasize, unsigned int padsize) 
499
                           unsigned int datasize, unsigned int padsize) 
387
    {
500
    {
388
        cout << "udi [" << udi << "] dicsize " << dicsize << " datasize "
501
        LOGDEB(("ScanSpacer: offs %u dicsz %u datasz %u padsz %u udi[%s]\n",
389
             << datasize << " padsize " << padsize << endl;
502
                (unsigned int)offs, dicsize, datasize, padsize, udi.c_str()));
390
        sizeseen += CIRCACHE_HEADER_SIZE + dicsize + datasize + padsize;
503
        sizeseen += CIRCACHE_HEADER_SIZE + dicsize + datasize + padsize;
391
        if (sizeseen >= sizewanted)
504
        if (sizeseen >= sizewanted)
392
            return Stop;
505
            return Stop;
393
        return Continue;
506
        return Continue;
394
    }
507
    }
...
...
423
    int nsize = CIRCACHE_HEADER_SIZE + dic.size() + data.size();
536
    int nsize = CIRCACHE_HEADER_SIZE + dic.size() + data.size();
424
    int nwriteoffs = 0;
537
    int nwriteoffs = 0;
425
    int npadsize = 0;
538
    int npadsize = 0;
426
    bool extending = false;
539
    bool extending = false;
427
540
428
    cerr << "CirCache::PUT: nsize " << nsize << 
541
    LOGDEB2(("CirCache::put: nsize %d oheadoffs %d\n", 
429
        " oheadoffs " << m_d->m_oheadoffs << endl;
542
             nsize, m_d->m_oheadoffs));
430
543
431
    if (st.st_size < m_d->m_maxsize) {
544
    if (st.st_size < m_d->m_maxsize) {
432
        // If we are still growing the file, things are simple
545
        // If we are still growing the file, things are simple
433
        nwriteoffs = lseek(m_d->m_fd, 0, SEEK_END);
546
        nwriteoffs = lseek(m_d->m_fd, 0, SEEK_END);
434
        npadsize = 0;
547
        npadsize = 0;
...
...
448
            if (m_d->readentryheader(m_d->m_nheadoffs, pd) != 
561
            if (m_d->readentryheader(m_d->m_nheadoffs, pd) != 
449
                CCScanHook::Continue) {
562
                CCScanHook::Continue) {
450
                return false;
563
                return false;
451
            }
564
            }
452
            assert(int(pd.padsize) == m_d->m_npadsize);
565
            assert(int(pd.padsize) == m_d->m_npadsize);
453
            cerr << "CirCache::put: recovering previous padsize " << 
566
            LOGDEB2(("CirCache::put: recovering previous padsize %d\n",
454
                pd.padsize << endl;
567
                     pd.padsize));
455
            pd.padsize = 0;
568
            pd.padsize = 0;
456
            if (!m_d->writeentryheader(m_d->m_nheadoffs, pd)) {
569
            if (!m_d->writeentryheader(m_d->m_nheadoffs, pd)) {
457
                return false;
570
                return false;
458
            }
571
            }
459
            nwriteoffs = m_d->m_oheadoffs - recovpadsize;
572
            nwriteoffs = m_d->m_oheadoffs - recovpadsize;
...
...
461
        }
574
        }
462
575
463
        if (nsize <= recovpadsize) {
576
        if (nsize <= recovpadsize) {
464
            // If the new entry fits entirely in the pad area from the
577
            // If the new entry fits entirely in the pad area from the
465
            // latest one, no need to recycle the oldest entries.
578
            // latest one, no need to recycle the oldest entries.
466
            cerr << "CirCache::put: new fits in old padsize " << 
579
            LOGDEB2(("CirCache::put: new fits in old padsize %d\n,"
467
                recovpadsize << endl;
580
                     recovpadsize));
468
            npadsize = recovpadsize - nsize;
581
            npadsize = recovpadsize - nsize;
469
        } else {
582
        } else {
470
            // Scan the file until we have enough space for the new entry,
583
            // Scan the file until we have enough space for the new entry,
471
            // and determine the pad size up to the 1st preserved entry
584
            // and determine the pad size up to the 1st preserved entry
472
            int scansize = nsize - recovpadsize;
585
            int scansize = nsize - recovpadsize;
473
            cerr << "CirCache::put: scanning for size " << scansize << 
586
            LOGDEB2(("CirCache::put: scanning for size %d from offs %u\n",
474
                " from offset " << m_d->m_oheadoffs << endl;
587
                    scansize, (unsigned int)m_d->m_oheadoffs));
475
            CCScanHookSpacer spacer(scansize);
588
            CCScanHookSpacer spacer(scansize);
476
            switch (m_d->scan(m_d->m_oheadoffs, &spacer)) {
589
            switch (m_d->scan(m_d->m_oheadoffs, &spacer)) {
477
            case CCScanHook::Stop: 
590
            case CCScanHook::Stop: 
478
                cerr << "put: Scan ok, sizeseen " << spacer.sizeseen << endl;
591
                LOGDEB2(("CirCache::put: Scan ok, sizeseen %d\n", 
592
                         spacer.sizeseen));
479
                npadsize = spacer.sizeseen - scansize;
593
                npadsize = spacer.sizeseen - scansize;
480
                break;
594
                break;
481
            case CCScanHook::Eof:
595
            case CCScanHook::Eof:
482
                // npadsize is 0
596
                // npadsize is 0
483
                extending = true;
597
                extending = true;
...
...
487
                return false;
601
                return false;
488
            }
602
            }
489
        }
603
        }
490
    }
604
    }
491
    
605
    
492
    cerr << "CirCache::put: writing " << nsize << " at " << nwriteoffs << 
606
    LOGDEB2(("CirCache::put: writing %d at %d padsize %d\n", 
493
        " padsize " << npadsize << endl;
607
             nsize, nwriteoffs, npadsize));
494
    if (lseek(m_d->m_fd, nwriteoffs, 0) != nwriteoffs) {
608
    if (lseek(m_d->m_fd, nwriteoffs, 0) != nwriteoffs) {
495
        m_d->m_reason << "CirCache::put: lseek failed: " << errno;
609
        m_d->m_reason << "CirCache::put: lseek failed: " << errno;
496
        return false;
610
        return false;
497
    }
611
    }
498
    char *bf = m_d->buf(CIRCACHE_HEADER_SIZE);
612
    char *bf = m_d->buf(CIRCACHE_HEADER_SIZE);
...
...
549
static char *thisprog;
663
static char *thisprog;
550
664
551
static char usage [] =
665
static char usage [] =
552
" -c <dirname> : create\n"
666
" -c <dirname> : create\n"
553
" -p <dirname> <apath> [apath ...] : put files\n"
667
" -p <dirname> <apath> [apath ...] : put files\n"
668
" -d <dirname> : dump\n"
669
" -g [-i instance] <dirname> <udi>: get\n"
554
;
670
;
555
static void
671
static void
556
Usage(FILE *fp = stderr)
672
Usage(FILE *fp = stderr)
557
{
673
{
558
    fprintf(fp, "%s: usage:\n%s", thisprog, usage);
674
    fprintf(fp, "%s: usage:\n%s", thisprog, usage);
...
...
560
}
676
}
561
677
562
static int     op_flags;
678
static int     op_flags;
563
#define OPT_MOINS 0x1
679
#define OPT_MOINS 0x1
564
#define OPT_c     0x2 
680
#define OPT_c     0x2 
565
#define OPT_b   0x4 
566
#define OPT_p     0x8
681
#define OPT_p     0x8
567
#define OPT_g     0x10
682
#define OPT_g     0x10
683
#define OPT_d     0x20
684
#define OPT_i     0x40
568
685
569
int main(int argc, char **argv)
686
int main(int argc, char **argv)
570
{
687
{
571
  int count = 10;
688
  int instance = -1;
572
    
689
573
  thisprog = argv[0];
690
  thisprog = argv[0];
574
  argc--; argv++;
691
  argc--; argv++;
575
692
576
  while (argc > 0 && **argv == '-') {
693
  while (argc > 0 && **argv == '-') {
577
    (*argv)++;
694
    (*argv)++;
...
...
581
    while (**argv)
698
    while (**argv)
582
      switch (*(*argv)++) {
699
      switch (*(*argv)++) {
583
      case 'c': op_flags |= OPT_c; break;
700
      case 'c': op_flags |= OPT_c; break;
584
      case 'p': op_flags |= OPT_p; break;
701
      case 'p': op_flags |= OPT_p; break;
585
      case 'g': op_flags |= OPT_g; break;
702
      case 'g': op_flags |= OPT_g; break;
703
      case 'd':   op_flags |= OPT_d; break;
586
      case 'b':  op_flags |= OPT_b; if (argc < 2)  Usage();
704
      case 'i':  op_flags |= OPT_i; if (argc < 2)  Usage();
587
    if ((sscanf(*(++argv), "%d", &count)) != 1) 
705
    if ((sscanf(*(++argv), "%d", &instance)) != 1) 
588
      Usage(); 
706
      Usage(); 
589
    argc--; 
707
    argc--; 
590
    goto b1;
708
    goto b1;
591
      default: Usage(); break;
709
      default: Usage(); break;
592
      }
710
      }
...
...
631
              exit(1);
749
              exit(1);
632
          }
750
          }
633
      }
751
      }
634
      cc.open(CirCache::CC_OPREAD);
752
      cc.open(CirCache::CC_OPREAD);
635
  } else if (op_flags & OPT_g) {
753
  } else if (op_flags & OPT_g) {
754
      string udi = *argv++;argc--;
636
      if (!cc.open(CirCache::CC_OPREAD)) {
755
      if (!cc.open(CirCache::CC_OPREAD)) {
637
          cerr << "Open failed: " << cc.getReason() << endl;
756
          cerr << "Open failed: " << cc.getReason() << endl;
638
          exit(1);
757
          exit(1);
639
      }
758
      }
759
      string dic, data;
760
      if (!cc.get(udi, dic, data, instance)) {
761
          cerr << "Get failed: " << cc.getReason() << endl;
762
          exit(1);
763
      }
764
      cout << "Dict: [" << dic << "]" << endl;
765
  } else if (op_flags & OPT_d) {
766
      if (!cc.open(CirCache::CC_OPREAD)) {
767
          cerr << "Open failed: " << cc.getReason() << endl;
768
          exit(1);
769
      }
770
      cc.dump();
640
  } else
771
  } else
641
      Usage();
772
      Usage();
642
773
643
  exit(0);
774
  exit(0);
644
}
775
}