memfile_lease_mgr.cc 22.6 KB
Newer Older
1
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
2
3
4
5
6
7
8
9
10
11
12
13
14
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
#include <dhcpsrv/cfgmgr.h>
16
#include <dhcpsrv/dhcpsrv_log.h>
17
#include <dhcpsrv/lease_file_loader.h>
18
#include <dhcpsrv/memfile_lease_mgr.h>
19
#include <exceptions/exceptions.h>
20
#include <util/process_spawn.h>
21
#include <cstdio>
22
#include <iostream>
23
#include <sstream>
24

25
26
27
28
29
namespace {

/// @brief Maximum number of errors to read the leases from the lease file.
const uint32_t MAX_LEASE_ERRORS = 100;

30
31
const char* KEA_LFC_EXECUTABLE_ENV_NAME = "KEA_LFC_EXECUTABLE";

32
33
} // end of anonymous namespace

34
using namespace isc;
35
using namespace isc::dhcp;
36
using namespace isc::util;
37

38
Memfile_LeaseMgr::Memfile_LeaseMgr(const ParameterMap& parameters)
39
40
    : LeaseMgr(parameters), lfc_timer_(*getIOService()),
      lfc_process_() {
41
42
43
44
45
    // Check the universe and use v4 file or v6 file.
    std::string universe = getParameter("universe");
    if (universe == "4") {
        std::string file4 = initLeaseFilePath(V4);
        if (!file4.empty()) {
46
47
            loadLeasesFromFiles<Lease4, CSVLeaseFile4>(file4, lease_file4_,
                                                       storage4_);
48
49
50
51
        }
    } else {
        std::string file6 = initLeaseFilePath(V6);
        if (!file6.empty()) {
52
53
            loadLeasesFromFiles<Lease6, CSVLeaseFile6>(file6, lease_file6_,
                                                       storage6_);
54
        }
55
    }
56
57
58
59
60

    // If lease persistence have been disabled for both v4 and v6,
    // issue a warning. It is ok not to write leases to disk when
    // doing testing, but it should not be done in normal server
    // operation.
61
   if (!persistLeases(V4) && !persistLeases(V6)) {
62
        LOG_WARN(dhcpsrv_logger, DHCPSRV_MEMFILE_NO_STORAGE);
63
64

    } else  {
65
        lfcSetup();
66
    }
67
68
69
}

Memfile_LeaseMgr::~Memfile_LeaseMgr() {
70
71
72
73
74
75
76
77
    if (lease_file4_) {
        lease_file4_->close();
        lease_file4_.reset();
    }
    if (lease_file6_) {
        lease_file6_->close();
        lease_file6_.reset();
    }
78
79
}

80
81
bool
Memfile_LeaseMgr::addLease(const Lease4Ptr& lease) {
82
83
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_ADD_ADDR4).arg(lease->addr_.toText());
84

85
86
87
88
    if (getLease4(lease->addr_)) {
        // there is a lease with specified address already
        return (false);
    }
89
90
91
92

    // Try to write a lease to disk first. If this fails, the lease will
    // not be inserted to the memory and the disk and in-memory data will
    // remain consistent.
93
    if (persistLeases(V4)) {
94
95
96
        lease_file4_->append(*lease);
    }

97
98
    storage4_.insert(lease);
    return (true);
99
100
}

101
102
bool
Memfile_LeaseMgr::addLease(const Lease6Ptr& lease) {
103
104
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_ADD_ADDR6).arg(lease->addr_.toText());
105

106
    if (getLease6(lease->type_, lease->addr_)) {
107
108
109
        // there is a lease with specified address already
        return (false);
    }
110
111
112
113

    // Try to write a lease to disk first. If this fails, the lease will
    // not be inserted to the memory and the disk and in-memory data will
    // remain consistent.
114
    if (persistLeases(V6)) {
115
116
117
        lease_file6_->append(*lease);
    }

118
119
120
121
    storage6_.insert(lease);
    return (true);
}

122
123
Lease4Ptr
Memfile_LeaseMgr::getLease4(const isc::asiolink::IOAddress& addr) const {
124
125
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_GET_ADDR4).arg(addr.toText());
126

127
128
129
    typedef Lease4Storage::nth_index<0>::type SearchIndex;
    const SearchIndex& idx = storage4_.get<0>();
    Lease4Storage::iterator l = idx.find(addr);
130
131
132
    if (l == storage4_.end()) {
        return (Lease4Ptr());
    } else {
133
        return (Lease4Ptr(new Lease4(**l)));
134
    }
135
136
}

137
138
Lease4Collection
Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const {
139
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
140
              DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText());
141
142
143
144
145
146
147
    typedef Lease4Storage::nth_index<0>::type SearchIndex;
    Lease4Collection collection;
    const SearchIndex& idx = storage4_.get<0>();
    for(SearchIndex::const_iterator lease = idx.begin();
        lease != idx.end(); ++lease) {

        // Every Lease4 has a hardware address, so we can compare it
148
        if ( (*(*lease)->hwaddr_) == hwaddr) {
149
            collection.push_back((*lease));
150
151
        }
    }
152

153
    return (collection);
154
155
}

156
157
Lease4Ptr
Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr, SubnetID subnet_id) const {
158
159
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_GET_SUBID_HWADDR).arg(subnet_id)
160
161
        .arg(hwaddr.toText());

162
163
164
    // We are going to use index #1 of the multi index container.
    // We define SearchIndex locally in this function because
    // currently only this function uses this index.
165
    typedef Lease4Storage::nth_index<1>::type SearchIndex;
166
    // Get the index.
167
    const SearchIndex& idx = storage4_.get<1>();
168
169
170
171
    // Try to find the lease using HWAddr and subnet id.
    SearchIndex::const_iterator lease =
        idx.find(boost::make_tuple(hwaddr.hwaddr_, subnet_id));
    // Lease was not found. Return empty pointer to the caller.
172
    if (lease == idx.end()) {
173
        return (Lease4Ptr());
174
175
    }

176
    // Lease was found. Return it to the caller.
177
    return (Lease4Ptr(new Lease4(**lease)));
178
179
}

180
Lease4Collection
181
Memfile_LeaseMgr::getLease4(const ClientId& client_id) const {
182
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
183
              DHCPSRV_MEMFILE_GET_CLIENTID).arg(client_id.toText());
184
    typedef Lease4Storage::nth_index<0>::type SearchIndex;
185
186
187
188
189
190
191
    Lease4Collection collection;
    const SearchIndex& idx = storage4_.get<0>();
    for(SearchIndex::const_iterator lease = idx.begin();
        lease != idx.end(); ++ lease) {

        // client-id is not mandatory in DHCPv4. There can be a lease that does
        // not have a client-id. Dereferencing null pointer would be a bad thing
192
193
        if((*lease)->client_id_ && *(*lease)->client_id_ == client_id) {
            collection.push_back((*lease));
194
195
196
197
        }
    }

    return (collection);
198
}
199

200
201
Lease4Ptr
Memfile_LeaseMgr::getLease4(const ClientId& client_id,
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
                            const HWAddr& hwaddr,
                            SubnetID subnet_id) const {
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_GET_CLIENTID_HWADDR_SUBID).arg(client_id.toText())
                                                        .arg(hwaddr.toText())
                                                        .arg(subnet_id);

    // We are going to use index #3 of the multi index container.
    // We define SearchIndex locally in this function because
    // currently only this function uses this index.
    typedef Lease4Storage::nth_index<3>::type SearchIndex;
    // Get the index.
    const SearchIndex& idx = storage4_.get<3>();
    // Try to get the lease using client id, hardware address and subnet id.
    SearchIndex::const_iterator lease =
        idx.find(boost::make_tuple(client_id.getClientId(), hwaddr.hwaddr_,
                                   subnet_id));

    if (lease == idx.end()) {
        // Lease was not found. Return empty pointer to the caller.
        return (Lease4Ptr());
    }

    // Lease was found. Return it to the caller.
    return (*lease);
}

Lease4Ptr
Memfile_LeaseMgr::getLease4(const ClientId& client_id,
                            SubnetID subnet_id) const {
232
233
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_GET_SUBID_CLIENTID).arg(subnet_id)
234
              .arg(client_id.toText());
235

236
237
238
    // We are going to use index #2 of the multi index container.
    // We define SearchIndex locally in this function because
    // currently only this function uses this index.
239
    typedef Lease4Storage::nth_index<2>::type SearchIndex;
240
    // Get the index.
241
    const SearchIndex& idx = storage4_.get<2>();
242
243
244
245
    // Try to get the lease using client id and subnet id.
    SearchIndex::const_iterator lease =
        idx.find(boost::make_tuple(client_id.getClientId(), subnet_id));
    // Lease was not found. Return empty pointer to the caller.
246
    if (lease == idx.end()) {
247
        return (Lease4Ptr());
248
    }
249
    // Lease was found. Return it to the caller.
250
    return (Lease4Ptr(new Lease4(**lease)));
251
252
}

253
Lease6Ptr
254
Memfile_LeaseMgr::getLease6(Lease::Type type,
255
                            const isc::asiolink::IOAddress& addr) const {
256
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
257
258
259
              DHCPSRV_MEMFILE_GET_ADDR6)
        .arg(addr.toText())
        .arg(Lease::typeToText(type));
260
    Lease6Storage::iterator l = storage6_.find(addr);
261
    if (l == storage6_.end() || !(*l) || ((*l)->type_ != type)) {
262
263
        return (Lease6Ptr());
    } else {
264
        return (Lease6Ptr(new Lease6(**l)));
265
266
267
    }
}

268
Lease6Collection
269
Memfile_LeaseMgr::getLeases6(Lease::Type type,
270
                            const DUID& duid, uint32_t iaid) const {
271
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
272
273
274
275
              DHCPSRV_MEMFILE_GET_IAID_DUID)
        .arg(iaid)
        .arg(duid.toText())
        .arg(Lease::typeToText(type));
276

277
278
279
280
281
282
283
284
285
286
287
    // We are going to use index #1 of the multi index container.
    typedef Lease6Storage::nth_index<1>::type SearchIndex;
    // Get the index.
    const SearchIndex& idx = storage6_.get<1>();
    // Try to get the lease using the DUID, IAID and lease type.
    std::pair<SearchIndex::iterator, SearchIndex::iterator> l =
        idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
    Lease6Collection collection;
    for(SearchIndex::iterator lease = l.first; lease != l.second; ++lease) {
        collection.push_back(Lease6Ptr(new Lease6(**lease)));
    }
288

289
    return (collection);
290
291
}

292
Lease6Collection
293
Memfile_LeaseMgr::getLeases6(Lease::Type type,
294
295
                             const DUID& duid, uint32_t iaid,
                             SubnetID subnet_id) const {
296
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
297
              DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID)
298
299
300
301
        .arg(iaid)
        .arg(subnet_id)
        .arg(duid.toText())
        .arg(Lease::typeToText(type));
302

303
304
305
306
    // We are going to use index #1 of the multi index container.
    typedef Lease6Storage::nth_index<1>::type SearchIndex;
    // Get the index.
    const SearchIndex& idx = storage6_.get<1>();
307
308
309
310
311
312
313
314
315
    // Try to get the lease using the DUID, IAID and lease type.
    std::pair<SearchIndex::iterator, SearchIndex::iterator> l =
        idx.equal_range(boost::make_tuple(duid.getDuid(), iaid, type));
    Lease6Collection collection;
    for(SearchIndex::iterator lease = l.first; lease != l.second; ++lease) {
        // Filter out the leases which subnet id doesn't match.
        if((*lease)->subnet_id_ == subnet_id) {
            collection.push_back(Lease6Ptr(new Lease6(**lease)));
        }
316
    }
317
318

    return (collection);
319
320
}

321
322
void
Memfile_LeaseMgr::updateLease4(const Lease4Ptr& lease) {
323
324
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_UPDATE_ADDR4).arg(lease->addr_.toText());
325

326
327
328
    Lease4Storage::iterator lease_it = storage4_.find(lease->addr_);
    if (lease_it == storage4_.end()) {
        isc_throw(NoSuchLease, "failed to update the lease with address "
329
                  << lease->addr_ << " - no such lease");
330
    }
331
332
333
334

    // Try to write a lease to disk first. If this fails, the lease will
    // not be inserted to the memory and the disk and in-memory data will
    // remain consistent.
335
    if (persistLeases(V4)) {
336
337
338
        lease_file4_->append(*lease);
    }

339
    **lease_it = *lease;
340
341
}

342
343
void
Memfile_LeaseMgr::updateLease6(const Lease6Ptr& lease) {
344
345
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_UPDATE_ADDR6).arg(lease->addr_.toText());
346

347
348
349
    Lease6Storage::iterator lease_it = storage6_.find(lease->addr_);
    if (lease_it == storage6_.end()) {
        isc_throw(NoSuchLease, "failed to update the lease with address "
350
                  << lease->addr_ << " - no such lease");
351
    }
352
353
354
355

    // Try to write a lease to disk first. If this fails, the lease will
    // not be inserted to the memory and the disk and in-memory data will
    // remain consistent.
356
    if (persistLeases(V6)) {
357
358
359
        lease_file6_->append(*lease);
    }

360
    **lease_it = *lease;
361
362
}

363
364
bool
Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
365
366
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_DELETE_ADDR).arg(addr.toText());
367
    if (addr.isV4()) {
368
369
370
371
372
373
        // v4 lease
        Lease4Storage::iterator l = storage4_.find(addr);
        if (l == storage4_.end()) {
            // No such lease
            return (false);
        } else {
374
            if (persistLeases(V4)) {
375
376
377
378
379
380
381
382
                // Copy the lease. The valid lifetime needs to be modified and
                // we don't modify the original lease.
                Lease4 lease_copy = **l;
                // Setting valid lifetime to 0 means that lease is being
                // removed.
                lease_copy.valid_lft_ = 0;
                lease_file4_->append(lease_copy);
            }
383
384
385
            storage4_.erase(l);
            return (true);
        }
386

387
    } else {
388
        // v6 lease
389
390
391
392
393
        Lease6Storage::iterator l = storage6_.find(addr);
        if (l == storage6_.end()) {
            // No such lease
            return (false);
        } else {
394
            if (persistLeases(V6)) {
395
396
397
398
399
400
401
402
403
                // Copy the lease. The lifetimes need to be modified and we
                // don't modify the original lease.
                Lease6 lease_copy = **l;
                // Setting lifetimes to 0 means that lease is being removed.
                lease_copy.valid_lft_ = 0;
                lease_copy.preferred_lft_ = 0;
                lease_file6_->append(lease_copy);
            }

404
405
406
            storage6_.erase(l);
            return (true);
        }
407
408
409
    }
}

410
411
std::string
Memfile_LeaseMgr::getDescription() const {
412
413
414
415
    return (std::string("This is a dummy memfile backend implementation.\n"
                        "It does not offer any useful lease management and its only\n"
                        "purpose is to test abstract lease manager API."));
}
416
417
418

void
Memfile_LeaseMgr::commit() {
419
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, DHCPSRV_MEMFILE_COMMIT);
420
421
422
423
}

void
Memfile_LeaseMgr::rollback() {
424
425
    LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL,
              DHCPSRV_MEMFILE_ROLLBACK);
426
}
427

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
std::string
Memfile_LeaseMgr::appendSuffix(const std::string& file_name,
                               const LFCFileType& file_type) {
    std::string name(file_name);
    switch (file_type) {
    case FILE_INPUT:
        name += ".1";
        break;
    case FILE_PREVIOUS:
        name += ".2";
        break;
    case FILE_OUTPUT:
        name += ".output";
        break;
    case FILE_FINISH:
        name += ".completed";
        break;
445
446
447
    case FILE_PID:
        name += ".pid";
        break;
448
449
450
451
452
453
454
455
456
    default:
        // Do not append any suffix for the FILE_CURRENT.
        ;
    }

    return (name);
}


457
458
459
460
461
uint32_t
Memfile_LeaseMgr::getIOServiceExecInterval() const {
    return (static_cast<uint32_t>(lfc_timer_.getInterval() / 1000));
}

462
463
464
465
466
467
468
469
470
std::string
Memfile_LeaseMgr::getDefaultLeaseFilePath(Universe u) const {
    std::ostringstream s;
    s << CfgMgr::instance().getDataDir() << "/kea-leases";
    s << (u == V4 ? "4" : "6");
    s << ".csv";
    return (s.str());
}

471
472
473
474
475
476
477
478
479
std::string
Memfile_LeaseMgr::getLeaseFilePath(Universe u) const {
    if (u == V4) {
        return (lease_file4_ ? lease_file4_->getFilename() : "");
    }

    return (lease_file6_ ? lease_file6_->getFilename() : "");
}

480
481
bool
Memfile_LeaseMgr::persistLeases(Universe u) const {
482
483
484
485
486
487
488
489
    // Currently, if the lease file IO is not created, it means that writes to
    // disk have been explicitly disabled by the administrator. At some point,
    // there may be a dedicated ON/OFF flag implemented to control this.
    if (u == V4 && lease_file4_) {
        return (true);
    }

    return (u == V6 && lease_file6_);
490
491
492
493
}

std::string
Memfile_LeaseMgr::initLeaseFilePath(Universe u) {
494
    std::string persist_val;
495
    try {
496
        persist_val = getParameter("persist");
497
    } catch (const Exception& ex) {
498
499
        // If parameter persist hasn't been specified, we use a default value
        // 'yes'.
500
        persist_val = "true";
501
    }
502
    // If persist_val is 'false' we will not store leases to disk, so let's
503
    // return empty file name.
504
    if (persist_val == "false") {
505
        return ("");
506

507
508
509
    } else if (persist_val != "true") {
        isc_throw(isc::BadValue, "invalid value 'persist="
                  << persist_val << "'");
510
511
    }

512
513
    std::string lease_file;
    try {
514
        lease_file = getParameter("name");
515
516
517
518
519
    } catch (const Exception& ex) {
        lease_file = getDefaultLeaseFilePath(u);
    }
    return (lease_file);
}
520

521
void
522
Memfile_LeaseMgr::lfcSetup() {
523
524
525
526
527
528
529
530
531
532
533
    std::string lfc_interval_str = "0";
    try {
        lfc_interval_str = getParameter("lfc-interval");
    } catch (const std::exception& ex) {
        // Ignore and default to 0.
    }

    uint32_t lfc_interval = 0;
    try {
        lfc_interval = boost::lexical_cast<uint32_t>(lfc_interval_str);
    } catch (boost::bad_lexical_cast& ex) {
534
        isc_throw(isc::BadValue, "invalid value of the lfc-interval "
535
536
537
                  << lfc_interval_str << " specified");
    }

538
539
    // If LFC is enabled, we have to setup the interval timer and prepare for
    // executing the kea-lfc process.
540
    if (lfc_interval > 0) {
541
542
543
        char* c_executable = getenv(KEA_LFC_EXECUTABLE_ENV_NAME);

        // Set the timer to call callback function periodically.
544
545
        asiolink::IntervalTimer::Callback cb =
            boost::bind(&Memfile_LeaseMgr::lfcCallback, this);
546
        LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_SETUP).arg(lfc_interval);
547
        lfc_timer_.setup(cb, lfc_interval * 1000);
548
549
550
551
552
553
554
555
556
557
558
559

        // Start preparing the command line for kea-lfc.

        // Gather the base file name.
        std::string lease_file = lease_file4_ ? lease_file4_->getFilename() :
            lease_file6_->getFilename();

        // Create the other names by appending suffixes to the base name.
        util::ProcessArgs args;
        // Universe: v4 or v6.
        args.push_back(lease_file4_ ? "-4" : "-6");
        // Previous file.
560
        args.push_back("-x");
561
562
563
564
565
566
567
568
569
570
        args.push_back(appendSuffix(lease_file, FILE_PREVIOUS));
        // Input file.
        args.push_back("-i");
        args.push_back(appendSuffix(lease_file, FILE_INPUT));
        // Output file.
        args.push_back("-o");
        args.push_back(appendSuffix(lease_file, FILE_OUTPUT));
        // Finish file.
        args.push_back("-f");
        args.push_back(appendSuffix(lease_file, FILE_FINISH));
571
572
573
574
        // PID file.
        args.push_back("-p");
        args.push_back(appendSuffix(lease_file, FILE_PID));

575
576
577
578
579
580
        // The configuration file is currently unused.
        args.push_back("-c");
        args.push_back("ignored-path");

        // Create the process (do not start it yet).
        lfc_process_.reset(new util::ProcessSpawn(std::string(c_executable), args));
581
582
583
    }
}

584

585
586
void
Memfile_LeaseMgr::lfcCallback() {
587
    LOG_INFO(dhcpsrv_logger, DHCPSRV_MEMFILE_LFC_START);
588
589
590
591
592
593
594
595
596
597
598
599
600
601

    // Check if we're in the v4 or v6 space and use the appropriate file.
    if (lease_file4_) {
        leaseFileCleanup(lease_file4_);

    } else if (lease_file6_) {
        leaseFileCleanup(lease_file6_);

    }
}

template<typename LeaseFileType>
void Memfile_LeaseMgr::
leaseFileCleanup(boost::shared_ptr<LeaseFileType>& lease_file) {
602
603
604
605
    // Check if the copy of the lease file exists already. If it does, it
    // is an indication that another LFC instance may be in progress, in
    // which case we don't want to rotate the current lease file to avoid
    // overriding the contents of the existing file.
606
607
    CSVFile lease_file_copy(appendSuffix(lease_file->getFilename(), FILE_INPUT));
    if (!lease_file_copy.exists()) {
608
        // Close the current file so as we can move it to the copy file.
609
        lease_file->close();
610
        // Move the current file to the copy file.
611
612
        rename(lease_file->getFilename().c_str(),
               lease_file_copy.getFilename().c_str());
613
        // Now that we moved the current file, we need to create a new one.
614
        lease_file.reset(new LeaseFileType(lease_file->getFilename()));
615
        // Leave the new file open for writing.
616
617
        lease_file->open();
    }
618
619
620
    // Once we have rotated files as needed, start the new kea-lfc process
    // to perform a cleanup.
    lfc_process_->spawn();
621
622
}

623
624
625
626
627
628
template<typename LeaseObjectType, typename LeaseFileType, typename StorageType>
void Memfile_LeaseMgr::
loadLeasesFromFiles(const std::string& filename,
                    boost::shared_ptr<LeaseFileType>& lease_file,
                    StorageType& storage) {
    storage.clear();
629

630
631
632
633
634
    // Load the leasefile.completed, if exists.
    lease_file.reset(new LeaseFileType(std::string(filename + ".completed")));
    if (lease_file->exists()) {
        LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
                                               MAX_LEASE_ERRORS);
635

636
637
638
    } else {
        // If the leasefile.completed doesn't exist, let's load the leases
        // from leasefile.2 and leasefile.1, if they exist.
639
        lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_PREVIOUS)));
640
641
642
        if (lease_file->exists()) {
            LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
                                                   MAX_LEASE_ERRORS);
643
644
        }

645
        lease_file.reset(new LeaseFileType(appendSuffix(filename, FILE_INPUT)));
646
        if (lease_file->exists()) {
647
            LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
648
                                                   MAX_LEASE_ERRORS);
649
        }
650
    }
651
652
653
654
655
656
657
658
659
660

    // Always load leases from the primary lease file. If the lease file
    // doesn't exist it will be created by the LeaseFileLoader. Note
    // that the false value passed as the last parameter to load
    // function causes the function to leave the file open after
    // it is parsed. This file will be used by the backend to record
    // future lease updates.
    lease_file.reset(new LeaseFileType(filename));
    LeaseFileLoader::load<LeaseObjectType>(*lease_file, storage,
                                           MAX_LEASE_ERRORS, false);;
661
}