summaryrefslogtreecommitdiffstats
path: root/metricsd/persistent_integer.cc
blob: 9fa5c1e31ad322751ba81eed66308a770e3fd79b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "persistent_integer.h"

#include <fcntl.h>

#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>

#include "constants.h"
#include "metrics/metrics_library.h"


namespace chromeos_metrics {

// Static class member instantiation.
bool PersistentInteger::testing_ = false;

PersistentInteger::PersistentInteger(const std::string& name) :
      value_(0),
      version_(kVersion),
      name_(name),
      synced_(false) {
  if (testing_) {
    backing_file_name_ = name_;
  } else {
    backing_file_name_ = metrics::kMetricsDirectory + name_;
  }
}

PersistentInteger::~PersistentInteger() {}

void PersistentInteger::Set(int64_t value) {
  value_ = value;
  Write();
}

int64_t PersistentInteger::Get() {
  // If not synced, then read.  If the read fails, it's a good idea to write.
  if (!synced_ && !Read())
    Write();
  return value_;
}

int64_t PersistentInteger::GetAndClear() {
  int64_t v = Get();
  Set(0);
  return v;
}

void PersistentInteger::Add(int64_t x) {
  Set(Get() + x);
}

void PersistentInteger::Write() {
  int fd = HANDLE_EINTR(open(backing_file_name_.c_str(),
                             O_WRONLY | O_CREAT | O_TRUNC,
                             S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH));
  PCHECK(fd >= 0) << "cannot open " << backing_file_name_ << " for writing";
  PCHECK((HANDLE_EINTR(write(fd, &version_, sizeof(version_))) ==
          sizeof(version_)) &&
         (HANDLE_EINTR(write(fd, &value_, sizeof(value_))) ==
          sizeof(value_)))
      << "cannot write to " << backing_file_name_;
  close(fd);
  synced_ = true;
}

bool PersistentInteger::Read() {
  int fd = HANDLE_EINTR(open(backing_file_name_.c_str(), O_RDONLY));
  if (fd < 0) {
    PLOG(WARNING) << "cannot open " << backing_file_name_ << " for reading";
    return false;
  }
  int32_t version;
  int64_t value;
  bool read_succeeded = false;
  if (HANDLE_EINTR(read(fd, &version, sizeof(version))) == sizeof(version) &&
      version == version_ &&
      HANDLE_EINTR(read(fd, &value, sizeof(value))) == sizeof(value)) {
    value_ = value;
    read_succeeded = true;
    synced_ = true;
  }
  close(fd);
  return read_succeeded;
}

void PersistentInteger::SetTestingMode(bool testing) {
  testing_ = testing;
}


}  // namespace chromeos_metrics