1 /*
2 * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team
3 *
4 * Distributable under the terms of either the Apache License (Version 2.0) or
5 * the GNU Lesser General Public License, as specified in the COPYING file.
6 *
7 * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
8 */
9 #include "CLucene/StdHeader.h"
10 #include "SegmentInfos.h"
11
12 #include "CLucene/store/Directory.h"
13 #include "CLucene/util/Misc.h"
14
15 CL_NS_USE(store)
CL_NS_USE(util)16 CL_NS_USE(util)
17 CL_NS_DEF(index)
18
19 SegmentInfo::SegmentInfo(const QString& Name, const int32_t DocCount,
20 CL_NS(store)::Directory* Dir)
21 : docCount(DocCount)
22 , dir(Dir)
23 {
24 //Func - Constructor. Initialises SegmentInfo.
25 //Pre - Name holds the unique name in the directory Dir
26 // DocCount holds the number of documents in the segment
27 // Dir holds the Directory where the segment resides
28 //Post - The instance has been created. name contains the duplicated string
29 // Name. docCount = DocCount and dir references Dir
30 name = Name;
31 }
32
~SegmentInfo()33 SegmentInfo::~SegmentInfo()
34 {
35 }
36
SegmentInfos(bool _deleteMembers)37 SegmentInfos::SegmentInfos(bool _deleteMembers)
38 : deleteMembers(_deleteMembers)
39 {
40 //Func - Constructor
41 //Pre - deleteMembers indicates if the instance to be created must delete
42 // all SegmentInfo instances it manages when the instance is destroyed
43 // or not true -> must delete, false may not delete
44 //Post - An instance of SegmentInfos has been created.
45
46 //initialize counter to 0
47 counter = 0;
48 version = Misc::currentTimeMillis();
49 }
50
~SegmentInfos()51 SegmentInfos::~SegmentInfos()
52 {
53 //Func - Destructor
54 //Pre - true
55 //Post - The instance has been destroyed. Depending on the constructor used
56 // the SegmentInfo instances that this instance managed have been
57 // deleted or not.
58
59 if (deleteMembers) {
60 segmentInfosType::iterator it;
61 for (it = infos.begin(); it != infos.end(); ++it)
62 _CLLDELETE(*it);
63 }
64 //Clear the list of SegmentInfo instances - make sure everything is deleted
65 infos.clear();
66 }
67
info(int32_t i) const68 SegmentInfo* SegmentInfos::info(int32_t i) const
69 {
70 //Func - Returns a reference to the i-th SegmentInfo in the list.
71 //Pre - i >= 0
72 //Post - A reference to the i-th SegmentInfo instance has been returned
73
74 CND_PRECONDITION(i >= 0, "i contains negative number");
75
76 //Get the i-th SegmentInfo instance
77 SegmentInfo *ret = infos.value(i, 0);
78
79 //Condition check to see if the i-th SegmentInfo has been retrieved
80 CND_CONDITION(ret != NULL, "No SegmentInfo instance found");
81
82 return ret;
83 }
84
clearto(size_t _min)85 void SegmentInfos::clearto(size_t _min)
86 {
87 // Make sure we actually need to remove
88 if (infos.size() > _min) {
89 segmentInfosType::iterator itr;
90 segmentInfosType::iterator eitr = infos.end();
91 segmentInfosType::iterator bitr = infos.begin() + _min;
92
93 for(itr = bitr; itr != eitr; ++itr)
94 _CLLDELETE((*itr));
95 infos.erase(bitr, eitr);
96 }
97 }
98
add(SegmentInfo * info)99 void SegmentInfos::add(SegmentInfo* info)
100 {
101 infos.push_back(info);
102 }
103
size() const104 int32_t SegmentInfos::size() const
105 {
106 return infos.size();
107 }
108
read(Directory * directory)109 void SegmentInfos::read(Directory* directory)
110 {
111 //Func - Reads segments file that resides in directory.
112 //Pre - directory contains a valid reference
113 //Post - The segments file has been read and for each segment found
114 // a SegmentsInfo intance has been created and stored.
115
116 //Open an IndexInput to the segments file and check if valid
117 IndexInput* input = directory->openInput(QLatin1String("segments"));
118 if (input) {
119 try {
120 int32_t format = input->readInt();
121 // file contains explicit format info
122 if (format < 0) {
123 // check that it is a format we can understand
124 if (format < FORMAT) {
125 TCHAR err[30];
126 _sntprintf(err, 30, _T("Unknown format version: %d"), format);
127 _CLTHROWT(CL_ERR_Runtime, err);
128 }
129 // read version
130 version = input->readLong();
131 // read counter
132 counter = input->readInt();
133 } else {
134 // file is in old format without explicit format info
135 counter = format;
136 }
137
138 //Temporary variable for storing the name of the segment
139 char aname[CL_MAX_PATH] = { 0 };
140 TCHAR tname[CL_MAX_PATH] = { 0 };
141
142 //read segmentInfos
143 for (int32_t i = input->readInt(); i > 0; --i) {
144 // read the name of the segment
145 input->readString(tname, CL_MAX_PATH);
146 STRCPY_TtoA(aname, tname, CL_MAX_PATH);
147
148 //Instantiate a new SegmentInfo Instance
149 SegmentInfo* si = _CLNEW SegmentInfo(QLatin1String(aname),
150 input->readInt(), directory);
151
152 //Condition check to see if si points to an instance
153 CND_CONDITION(si != NULL, "Memory allocation for si failed") ;
154
155 //store SegmentInfo si
156 infos.push_back(si);
157 }
158
159 if (format >= 0) {
160 // in old format the version number may be at the end of the file
161 if (input->getFilePointer() >= input->length()) {
162 // old file format without version number
163 version = Misc::currentTimeMillis();
164 } else {
165 // read version
166 version = input->readLong();
167 }
168 }
169 } _CLFINALLY (
170 //destroy the inputStream input. The destructor of IndexInput will
171 //also close the Inputstream input
172 _CLDELETE(input);
173 );
174 }
175 }
176
write(Directory * directory)177 void SegmentInfos::write(Directory* directory)
178 {
179 //Func - Writes a new segments file based upon the SegmentInfo instances it manages
180 //Pre - directory is a valid reference to a Directory
181 //Post - The new segment has been written to disk
182
183 //Open an IndexOutput to the segments file and check if valid
184 IndexOutput* output = directory->createOutput(QLatin1String("segments.new"));
185 if (output) {
186 try {
187 // write FORMAT
188 output->writeInt(FORMAT);
189 // every write changes the index
190 output->writeLong(++version);
191 // Write the counter
192 output->writeInt(counter);
193
194 // Write the number of SegmentInfo Instances which is equal to the number
195 // of segments in directory as each SegmentInfo manages a single segment
196 output->writeInt(infos.size());
197
198 //temporary value for wide segment name
199 TCHAR tname[CL_MAX_PATH];
200
201 //Iterate through all the SegmentInfo instances
202 for (uint32_t i = 0; i < infos.size(); ++i) {
203 //Retrieve the SegmentInfo
204 SegmentInfo *si = infos.value(i, 0);
205 //Condition check to see if si has been retrieved
206 CND_CONDITION(si != NULL, "No SegmentInfo instance found");
207
208 //Write the name of the current segment
209 int32_t count = si->name.toWCharArray(tname);
210 tname[count] = '\0';
211 output->writeString(tname, _tcslen(tname));
212
213 //Write the number of documents in the segment
214 output->writeInt(si->docCount);
215 }
216 } _CLFINALLY(
217 output->close();
218 _CLDELETE(output);
219 );
220
221 // install new segment info
222 directory->renameFile(QLatin1String("segments.new"),
223 QLatin1String("segments"));
224 }
225 }
226
227
readCurrentVersion(Directory * directory)228 int64_t SegmentInfos::readCurrentVersion(Directory* directory)
229 {
230 int32_t format = 0;
231 int64_t version = 0;
232 IndexInput* input = directory->openInput(QLatin1String("segments"));
233 try {
234 format = input->readInt();
235 if (format < 0){
236 if (format < FORMAT) {
237 TCHAR err[30];
238 _sntprintf(err, 30, _T("Unknown format version: %d"), format);
239 _CLTHROWT(CL_ERR_Runtime, err);
240 }
241 // read version
242 version = input->readLong();
243 }
244 } _CLFINALLY (
245 input->close();
246 _CLDELETE(input);
247 );
248
249 if (format < 0)
250 return version;
251
252 // We cannot be sure about the format of the file. Therefore we have to
253 // read the whole file and cannot simply seek to the version entry.
254 SegmentInfos segmentInfos;
255 segmentInfos.read(directory);
256 return segmentInfos.getVersion();
257 }
258
259 CL_NS_END
260