~drizzle-trunk/drizzle/development

1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
2
 *
3
 * PrimeBase Media Stream for MySQL
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
17
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
18
 *
19
 * Original author: Paul McCullagh
20
 * Continued development: Barry Leslie
21
 *
22
 * 2007-05-25
23
 *
24
 * H&G2JCtL
25
 *
26
 * Network interface.
27
 *
28
 */
29
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
30
#ifdef DRIZZLED
31
#include "config.h"
32
#include <drizzled/common.h>
33
#include <drizzled/session.h>
34
#endif
35
36
#include "cslib/CSConfig.h"
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
37
#include <inttypes.h>
38
1548.2.10 by Barry.Leslie at PrimeBase
Merge from trunk.
39
#include "defs_ms.h"
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
40
41
#include "cslib/CSGlobal.h"
42
#include "cslib/CSLog.h"
43
#include "cslib/CSStrUtil.h"
44
#include "cslib/CSHTTPStream.h"
45
#include "cslib/CSStream.h"
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
46
1548.2.10 by Barry.Leslie at PrimeBase
Merge from trunk.
47
#include "repository_ms.h"
48
#include "open_table_ms.h"
49
#include "connection_handler_ms.h"
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
50
#include "metadata_ms.h"
1548.2.3 by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability.
51
#include "parameters_ms.h"
1548.2.7 by Barry.Leslie at PrimeBase
Fixed some problems with transactions and drizzle.
52
#include "pbmsdaemon_ms.h"
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
53
54
/*
55
 * ---------------------------------------------------------------
56
 * REPOSITORY FILE
57
 */
58
59
MSRepoFile::MSRepoFile():
60
CSFile(),
61
myRepo(NULL),
62
isFileInUse(false),
63
nextFile(NULL),
64
iNextLink(NULL),
65
iPrevLink(NULL)
66
{
67
}
68
69
MSRepoFile::~MSRepoFile()
70
{
71
	close();
72
}
73
74
void MSRepoFile::updateGarbage(uint64_t size) 
75
{
76
	MSRepoHeadRec	repo_head;
77
	enter_();
78
79
	lock_(myRepo);
80
	myRepo->myGarbageCount += size;
81
	CS_SET_DISK_8(repo_head.rh_garbage_count_8, myRepo->myGarbageCount);
82
	ASSERT(myRepo->myGarbageCount <= myRepo->myRepoFileSize);
83
	write(&repo_head.rh_garbage_count_8, offsetof(MSRepoHeadRec, rh_garbage_count_8), 8);
84
	unlock_(myRepo);
85
	if (!myRepo->myRepoXLock) 
86
		myRepo->signalCompactor();
87
88
	exit_();
89
}
90
91
void MSRepoFile::updateAccess(MSBlobHeadPtr blob, uint64_t rep_offset) 
92
{
93
	time_t	now = time(NULL);
94
	uint32_t count = CS_GET_DISK_4(blob->rb_access_count_4) +1;
95
96
	CS_SET_DISK_4(blob->rb_last_access_4, now);
97
	CS_SET_DISK_4(blob->rb_access_count_4, count);
98
	write(&blob->rb_last_access_4, rep_offset + offsetof(MSBlobHeadRec, rb_last_access_4), 8);
99
	myRepo->myLastAccessTime = now;
100
}
101
102
uint64_t MSRepoFile::readBlobChunk(PBMSBlobIDPtr blob_id, uint64_t rep_offset, uint64_t blob_offset, uint64_t buffer_size, char *buffer)
103
{
104
	MSBlobHeadRec		blob_head;
105
	size_t				tfer;
106
	uint16_t				head_size;
107
	uint64_t				blob_size;
108
	uint32_t				ac;
109
	uint64_t				offset, blob_read =0;
110
111
	enter_();
112
113
	read(&blob_head, rep_offset, sizeof(MSBlobHeadRec), sizeof(MSBlobHeadRec));
114
	if (CS_GET_DISK_4(blob_head.rd_magic_4) != MS_BLOB_HEADER_MAGIC)
115
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
116
		
117
	blob_size = CS_GET_DISK_6(blob_head.rb_blob_repo_size_6);
118
	head_size = CS_GET_DISK_2(blob_head.rb_head_size_2);
119
	ac = CS_GET_DISK_4(blob_head.rb_auth_code_4);
120
	if (blob_id->bi_auth_code != ac)
121
		CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
122
123
	offset = rep_offset + blob_offset + head_size;
124
	
125
	if (blob_offset > blob_size)
126
		goto done;
127
	
128
	if ((blob_offset + buffer_size) > blob_size)
129
		buffer_size = blob_size - blob_offset;
130
		
131
	while (buffer_size > 0) {
132
		if (buffer_size <= (uint64_t) (SSIZE_MAX))
133
			tfer = (size_t) buffer_size;
134
		else
135
			tfer = SSIZE_MAX;
136
			
137
		read(buffer, offset, tfer, tfer);
138
		offset += (uint64_t) tfer;
139
		buffer += (uint64_t) tfer;
140
		buffer_size -= (uint64_t) tfer;
141
		blob_read += (uint64_t) tfer;
142
	}
143
144
	/* Only update the access timestamp when reading the first block: */
145
	if (!blob_offset) 
146
		updateAccess(&blob_head, rep_offset);
147
	
148
done:
149
	return_(blob_read);
150
}
151
152
void MSRepoFile::writeBlobChunk(PBMSBlobIDPtr blob_id, uint64_t rep_offset, uint64_t blob_offset, uint64_t data_size, char *data)
153
{
154
	size_t				tfer;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
155
	off64_t				offset;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
156
	MSBlobHeadRec		blob_head;
157
	uint16_t				head_size;
158
	uint64_t				blob_size;
159
	uint32_t				ac;
160
161
	enter_();
162
163
	read(&blob_head, rep_offset, sizeof(MSBlobHeadRec), sizeof(MSBlobHeadRec));
164
	if (CS_GET_DISK_4(blob_head.rd_magic_4) != MS_BLOB_HEADER_MAGIC)
165
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
166
167
	blob_size = CS_GET_DISK_6(blob_head.rb_blob_repo_size_6);
168
	head_size = CS_GET_DISK_2(blob_head.rb_head_size_2);
169
	ac = CS_GET_DISK_4(blob_head.rb_auth_code_4);
170
	if (blob_id->bi_auth_code != ac)
171
		CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
172
173
	if ((blob_offset + data_size) > blob_size) 
174
		CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB write size or offset");
175
176
	offset = (uint64_t) head_size + rep_offset + blob_offset;
177
		
178
	while (data_size > 0) {
179
		if (data_size <= (uint64_t) (SSIZE_MAX))
180
			tfer = (size_t) data_size;
181
		else
182
			tfer = SSIZE_MAX;
183
			
184
		write(data, offset, tfer);
185
		data += (uint64_t) tfer;
186
		offset += (uint64_t) tfer;
187
		data_size -= (uint64_t) tfer;
188
	}
189
190
	exit_();
191
}
192
193
void MSRepoFile::sendBlob(MSOpenTable *otab, uint64_t offset, uint64_t req_offset, uint64_t req_size, uint32_t auth_code, bool with_auth_code, bool info_only, CSHTTPOutputStream *stream)
194
{
195
	MSConnectionHandler	*me;
196
	size_t				tfer;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
197
	off64_t				start_offset = offset;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
198
	MSBlobHeadRec		blob_head;
199
	uint8_t				storage_type;
200
	uint16_t				head_size, meta_size;
201
	uint64_t				blob_data_size, local_blob_size, meta_offset;
202
	uint32_t				ac;
203
	char				num_str[CS_WIDTH_INT_64];
204
	bool				redirect = false;
205
	
206
207
	enter_();
208
	me = (MSConnectionHandler *) self;
209
210
	read(&blob_head, start_offset, sizeof(MSBlobHeadRec), sizeof(MSBlobHeadRec));
211
	local_blob_size = CS_GET_DISK_6(blob_head.rb_blob_repo_size_6);	// This is the size of the BLOB data in the repository. Can be 0 if the BLOB is stored some where else.
212
	blob_data_size = CS_GET_DISK_6(blob_head.rb_blob_data_size_6);// This is the actual size of the BLOB.
213
	head_size = CS_GET_DISK_2(blob_head.rb_head_size_2);
214
	meta_size = CS_GET_DISK_2(blob_head.rb_mdata_size_2);
215
	meta_offset = start_offset + CS_GET_DISK_2(blob_head.rb_mdata_offset_2);
216
	ac = CS_GET_DISK_4(blob_head.rb_auth_code_4);
217
	if ((with_auth_code && auth_code != ac) || (CS_GET_DISK_4(blob_head.rd_magic_4) != MS_BLOB_HEADER_MAGIC))
218
		CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
219
220
	storage_type = CS_GET_DISK_1(blob_head.rb_storage_type_1);
221
	
222
	if ((!info_only) && BLOB_IN_CLOUD(storage_type)) {
223
		CSString *redirect_url = NULL;
224
		CloudKeyRec key;
225
		getBlobKey(&blob_head, &key);
226
		redirect_url = 	otab->getDB()->myBlobCloud->cl_getDataURL(&key);	
227
		push_(redirect_url);
228
		stream->setStatus(301);
229
		stream->addHeader("Location", redirect_url->getCString());
230
		release_(redirect_url);
231
		redirect = true;
232
	} else
233
		stream->setStatus(200);
234
235
	if (storage_type == MS_STANDARD_STORAGE) {
236
		char hex_checksum[33];
237
		cs_bin_to_hex(33, hex_checksum, 16, blob_head.rb_blob_checksum_md5d.val);
238
		hex_checksum[32] = 0;
239
		stream->addHeader(MS_CHECKSUM_TAG, hex_checksum);
240
	}
241
	
242
	snprintf(num_str, CS_WIDTH_INT_64, "%"PRIu64"", blob_data_size);
243
	stream->addHeader(MS_BLOB_SIZE, num_str);
244
		
245
	snprintf(num_str, CS_WIDTH_INT_64, "%"PRIu32"", CS_GET_DISK_4(blob_head.rb_last_access_4));
246
	stream->addHeader(MS_LAST_ACCESS, num_str);
247
248
	snprintf(num_str, CS_WIDTH_INT_64, "%"PRIu32"", CS_GET_DISK_4(blob_head.rb_access_count_4));
249
	stream->addHeader(MS_ACCESS_COUNT, num_str);
250
	
251
	snprintf(num_str, CS_WIDTH_INT_64, "%"PRIu32"", CS_GET_DISK_4(blob_head.rb_create_time_4));
252
	stream->addHeader(MS_CREATION_TIME, num_str);
253
	
254
	snprintf(num_str, CS_WIDTH_INT_64, "%"PRIu32"", storage_type);
255
	stream->addHeader(MS_BLOB_TYPE, num_str);
256
	
257
	
258
	// Add the meta data headers.
259
	if (meta_size) {
260
		MetaData metadata;
261
		char *name, *value;
262
		
263
		read(otab->myOTBuffer, meta_offset, meta_size, meta_size);
264
		metadata.use_data(otab->myOTBuffer, meta_size);
265
		while ((name = metadata.findNext(&value))) {
266
			stream->addHeader(name, value);
267
		}
268
		
269
	}
270
		
271
  offset += (uint64_t) head_size + req_offset;
272
  local_blob_size -= req_offset;
273
  if (local_blob_size > req_size)
274
    local_blob_size = req_size;
275
276
	stream->setContentLength((redirect || info_only)?0:local_blob_size);
277
	stream->writeHead();
278
	me->replyPending = false;
279
280
	if ((!redirect) && !info_only) {
281
    
282
		while (local_blob_size > 0) {
283
			if (local_blob_size <=  MS_OT_BUFFER_SIZE)
284
				tfer = (size_t) local_blob_size;
285
			else
286
				tfer = MS_OT_BUFFER_SIZE;
287
			read(otab->myOTBuffer, offset, tfer, tfer);
288
			stream->write(otab->myOTBuffer, tfer);
289
			offset += (uint64_t) tfer;
290
			local_blob_size -= (uint64_t) tfer;
291
		}
292
	}
293
	stream->flush();
294
295
	if (!info_only) {
296
		// Should the time stamp be updated if only the BLOB info was requested?
297
		/* Update the access timestamp: */
298
		updateAccess(&blob_head, start_offset);
299
	}
300
	
301
	exit_();
302
}
303
304
void MSRepoFile::update_blob_header(MSOpenTable *otab, uint64_t offset, uint64_t blob_size, uint16_t head_size, uint16_t new_head_size)
305
{
306
	uint16_t	w_offset =  offsetof(MSBlobHeadRec, rb_ref_count_2);
307
	MSRepoPointersRec	ptr;
308
	enter_();
309
310
	ptr.rp_chars = otab->myOTBuffer;
311
	CS_SET_DISK_4(ptr.rp_head->rb_mod_time_4, time(NULL));
312
	
313
	if (head_size == new_head_size) {
314
		w_offset =  offsetof(MSBlobHeadRec, rb_ref_count_2);
315
		write(otab->myOTBuffer + w_offset, offset + w_offset, head_size - w_offset);
316
	} else {
317
		/* Copy to a new space, free the old: */
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
318
		off64_t			dst_offset;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
319
		CSStringBuffer	*buffer;
320
		uint16_t ref_count, ref_size;
321
		uint32_t tab_id;
322
		uint64_t blob_id;
323
		
324
		myRepo->myRepoDatabase->openWriteRepo(otab);
325
		dst_offset = otab->myWriteRepo->myRepoFileSize;
326
327
		/* Write the header. */
328
		otab->myWriteRepoFile->write(otab->myOTBuffer, dst_offset, new_head_size);
329
330
		/* We have an engine reference, copy the BLOB over: */
331
		new_(buffer, CSStringBuffer());
332
		push_(buffer);
333
		buffer->setLength(MS_COMPACTOR_BUFFER_SIZE);
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
334
		CSFile::transfer(RETAIN(otab->myWriteRepoFile), dst_offset + new_head_size, RETAIN(this), offset + head_size, blob_size, buffer->getBuffer(0), MS_COMPACTOR_BUFFER_SIZE);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
335
		release_(buffer);
336
337
#ifdef HAVE_ALIAS_SUPPORT
338
		/* Update the BLOB alias if required. */
339
		
340
		if (CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2)) {
341
			uint32_t alias_hash = CS_GET_DISK_4(ptr.rp_head->rb_alias_hash_4);
342
			myRepo->myRepoDatabase->moveBlobAlias(myRepo->myRepoID, offset, alias_hash, myRepo->myRepoID, dst_offset);
343
		}
344
#endif
345
346
		/* Update the references: */
347
		ref_size = CS_GET_DISK_1(ptr.rp_head->rb_ref_size_1);
348
		ref_count = CS_GET_DISK_2(ptr.rp_head->rb_ref_count_2);
349
		ptr.rp_chars += myRepo->myRepoBlobHeadSize;
350
		
351
		while (ref_count) {
352
			switch (CS_GET_DISK_2(ptr.rp_ref->rr_type_2)) {
353
				case MS_BLOB_FREE_REF:
354
					break;
355
				case MS_BLOB_TABLE_REF:
356
					tab_id = CS_GET_DISK_4(ptr.rp_tab_ref->tr_table_id_4);
357
					blob_id = CS_GET_DISK_6(ptr.rp_tab_ref->tr_blob_id_6);
358
359
					if (otab->getDBTable()->myTableID == tab_id)
360
						otab->getDBTable()->updateBlobHandle(otab, blob_id, otab->myWriteRepo->myRepoID, dst_offset, new_head_size);
361
					else {
362
						MSOpenTable *ref_otab;
363
364
						ref_otab = MSTableList::getOpenTableByID(myRepo->myRepoDatabase->myDatabaseID, tab_id);
365
						frompool_(ref_otab);
366
						ref_otab->getDBTable()->updateBlobHandle(ref_otab, blob_id, otab->myWriteRepo->myRepoID, dst_offset, new_head_size);
367
						backtopool_(ref_otab);
368
					}
369
					break;
370
				case MS_BLOB_DELETE_REF:
371
					break;
372
				default:
373
					break;
374
			}
375
			ptr.rp_chars += ref_size;
376
			ref_count--; 
377
		}
378
379
		otab->myWriteRepo->myRepoFileSize += new_head_size + blob_size;
380
381
		/* Free the old head: */
382
		ptr.rp_chars = otab->myOTBuffer;
383
		if (myRepo->lockedForBackup()) {
384
			// This is done to tell the backup process that this BLOB was moved
385
			// after the backup had started and needs to be backed up also. 
386
			// (The moved BLOB doesn't though because the change took place after the backup had begone.)
387
			CS_SET_DISK_1(ptr.rp_head->rb_status_1, MS_BLOB_MOVED);
388
			CS_SET_DISK_4(ptr.rp_head->rb_backup_id_4, myRepo->myRepoDatabase->backupID());
389
		} else
390
			CS_SET_DISK_1(ptr.rp_head->rb_status_1, MS_BLOB_DELETED);
391
		
392
		write(ptr.rp_chars + MS_BLOB_STAT_OFFS, offset + MS_BLOB_STAT_OFFS, head_size - MS_BLOB_STAT_OFFS);
393
			
394
#ifdef DO_NOT_WIPE_BLOB		
395
		// Why is the BLOB header data being wiped here?
396
		// The data may be needed for backup.
397
		ptr.rp_chars += myRepo->myRepoBlobHeadSize;
398
		memset(ptr.rp_chars, 0, head_size - myRepo->myRepoBlobHeadSize);
399
		
400
		w_offset =  offsetof(MSBlobHeadRec, rb_alias_hash_4);
401
		write(otab->myOTBuffer + w_offset, offset + w_offset, head_size - w_offset);
402
#endif
403
404
		/* Increment the garbage count: */
405
		updateGarbage(head_size + blob_size);
406
		
407
	}
408
	exit_();
409
}
410
411
void MSRepoFile::referenceBlob(MSOpenTable *otab, uint64_t offset, uint16_t head_size, uint32_t tab_id, uint64_t blob_id, uint64_t blob_ref_id, uint32_t auth_code, uint16_t col_index)
412
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
413
	CSMutex				*myLock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
414
	MSRepoPointersRec	ptr;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
415
	uint32_t				size, ref_count;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
416
	size_t				ref_size, read_size;
417
	MSRepoBlobRefPtr	free_ref = NULL;
418
	MSRepoBlobRefPtr	free2_ref = NULL;
419
	MSRepoTableRefPtr	tab_ref = NULL;
420
	uint16_t				new_head_size;
421
#ifdef HAVE_ALIAS_SUPPORT
422
	bool				reset_alias_index = false;
423
	char				blob_alias[BLOB_ALIAS_LENGTH];
424
#endif
425
	uint64_t				blob_size;
426
	
427
	enter_();
428
	/* Lock the BLOB: */
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
429
	myLock = &myRepo->myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
430
	lock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
431
	/* Read the header: */
432
	if (head_size > MS_OT_BUFFER_SIZE) {
433
		CSException::throwAssertion(CS_CONTEXT, "BLOB header overflow");
434
	}
435
	
436
	read_size = read(otab->myOTBuffer, offset, head_size, 0);
437
	ptr.rp_chars = otab->myOTBuffer;
438
	if (CS_GET_DISK_4(ptr.rp_head->rd_magic_4) != MS_BLOB_HEADER_MAGIC)
439
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
440
	if (read_size < myRepo->myRepoBlobHeadSize)
441
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB header incomplete");
442
	if ( ! IN_USE_BLOB_STATUS(CS_GET_DISK_1(ptr.rp_head->rb_status_1)))
443
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been deleted");
444
	if (CS_GET_DISK_4(ptr.rp_bytes + myRepo->myRepoBlobHeadSize - 4) != auth_code)
445
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB data does not match reference");
446
	/* Assume that what is here is correct: */
447
	if (head_size != CS_GET_DISK_2(ptr.rp_head->rb_head_size_2)) {
448
		head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
449
		if (head_size > MS_OT_BUFFER_SIZE) { // Could happen if the header was creatd with a different version of PBMS.
450
			CSException::throwAssertion(CS_CONTEXT, "BLOB header overflow");
451
		}
452
		read_size = read(otab->myOTBuffer, offset, head_size, myRepo->myRepoBlobHeadSize);
453
	}
454
	head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
455
	blob_size = CS_GET_DISK_6(ptr.rp_head->rb_blob_repo_size_6);
456
	if (read_size < head_size) {
457
		/* This should not happen, because the file has been recovered,
458
		 * which should have already adjusted the head and blob
459
		 * size.
460
		 * If this happens then the file must have been truncated an the BLOB has been
461
		 * lost so we set the blob size to zero.
462
		 */
463
		head_size = read_size;
464
		blob_size = 0;
465
		
466
	}
467
	ref_size = CS_GET_DISK_1(ptr.rp_head->rb_ref_size_1);
468
	ref_count = CS_GET_DISK_2(ptr.rp_head->rb_ref_count_2);
469
	
470
#ifdef HAVE_ALIAS_SUPPORT
471
	if (CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2)) {
472
		reset_alias_index = true;
473
		strcpy(blob_alias, otab->myOTBuffer + CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2));
474
	}
475
#endif
476
	
477
	size = head_size - myRepo->myRepoBlobHeadSize;
478
	if (size > ref_size * ref_count)
479
		size = ref_size * ref_count;
480
	CS_SET_DISK_4(ptr.rp_head->rb_last_ref_4, (uint32_t) time(NULL)); // Set the reference time
481
	CS_SET_DISK_1(ptr.rp_head->rb_status_1, MS_BLOB_REFERENCED); 
482
	ptr.rp_chars += myRepo->myRepoBlobHeadSize;
483
	while (size >= ref_size) {
484
		switch (CS_GET_DISK_2(ptr.rp_ref->rr_type_2)) {
485
			case MS_BLOB_FREE_REF:
486
				if (!free_ref)
487
					free_ref = ptr.rp_blob_ref;
488
				else if (!free2_ref)
489
					free2_ref = ptr.rp_blob_ref;
490
				break;
491
			case MS_BLOB_TABLE_REF:
492
#ifdef HAVE_ALIAS_SUPPORT
493
				reset_alias_index = false; // No need to reset the index if the BLOB is already referenced. (We don't care what table references it.)
494
#endif
495
				if (CS_GET_DISK_4(ptr.rp_tab_ref->tr_table_id_4) == tab_id &&
496
					CS_GET_DISK_6(ptr.rp_tab_ref->tr_blob_id_6) == blob_id)
497
					tab_ref = ptr.rp_tab_ref;
498
				break;
499
			case MS_BLOB_DELETE_REF: {
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
500
				uint32_t tab_index;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
501
502
				tab_index = CS_GET_DISK_2(ptr.rp_temp_ref->tp_del_ref_2);
503
				if (tab_index && tab_index < ref_count) {
504
					MSRepoTableRefPtr tr;
505
506
					tab_index--;
507
					tr = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepo->getRepoBlobHeadSize() + tab_index * ref_size);
508
					if (CS_GET_DISK_4(tr->tr_table_id_4) == tab_id &&
509
						CS_GET_DISK_6(tr->tr_blob_id_6) == blob_id) {
510
						CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);
511
						if (free_ref)
512
							free2_ref = free_ref;
513
						free_ref = ptr.rp_blob_ref;
514
					}
515
				}
516
				else if (tab_index == INVALID_INDEX) {
517
					/* The is a reference from the temporary log only!! */
518
					if (free_ref)
519
						free2_ref = free_ref;
520
					free_ref = ptr.rp_blob_ref;
521
				}
522
				break;
523
			}
524
			default: { // Must be a blob REF, check that the BLOB reference doesn't already exist.
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
525
				uint32_t tab_index;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
526
				tab_index = CS_GET_DISK_2(ptr.rp_blob_ref->er_table_2);
527
				
528
				if (tab_index && tab_index < ref_count) {
529
					MSRepoTableRefPtr tr;
530
531
					tab_index--;
532
					tr = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepo->getRepoBlobHeadSize() + tab_index * ref_size);
533
					if (CS_GET_DISK_4(tr->tr_table_id_4) == tab_id &&
534
						CS_GET_DISK_6(tr->tr_blob_id_6) == blob_id) {
535
						if (COMMIT_MASK(CS_GET_DISK_8(ptr.rp_blob_ref->er_blob_ref_id_8)) ==  blob_ref_id) {
536
							char message[100];
537
							snprintf(message, 100, "Duplicate BLOB reference: db_id: %"PRIu32", tab_id:%"PRIu32", blob_ref_id: %"PRIu64"\n", myRepo->myRepoDatabase->myDatabaseID, tab_id, blob_ref_id);
538
							/* The reference already exists so there is nothing to do... */
539
							self->myException.log(self, message);
540
							goto done;
541
						}
542
					}
543
				}
544
				break;
545
			}
546
		}
547
		ptr.rp_chars += ref_size;
548
		size -= ref_size;
549
	}
550
551
	// A BLOB reference needs to be added and if there is not
552
	// already a table reference then a table reference must be added
553
	// also.
554
	if (!free_ref || (!tab_ref && !free2_ref)) {
555
		size_t new_refs = (tab_ref)?1:2;
556
		ptr.rp_chars = otab->myOTBuffer;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
557
		size_t sp = MS_VAR_SPACE(ptr.rp_head);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
558
		
559
		if (sp > (new_refs * CS_GET_DISK_1(ptr.rp_head->rb_ref_size_1))) {
560
			sp = MS_MIN_BLOB_HEAD_SIZE;
561
		}
562
		
563
		if (MS_CAN_ADD_REFS(ptr.rp_head, new_refs)) {
564
			new_head_size = head_size;
565
566
		} else { // The header must be grown
567
			size_t new_size, max_refs;
568
569
			if (ref_count < 2)
570
				max_refs = 4;
571
			else if (ref_count > 32)
572
				max_refs = ref_count + 32;
573
			else
574
				max_refs = 2 * ref_count;
575
				
576
			if (max_refs > (MS_OT_BUFFER_SIZE/ref_size))
577
				max_refs = (MS_OT_BUFFER_SIZE/ref_size);
578
				
579
			if (max_refs < (ref_count + new_refs))
580
				CSException::throwAssertion(CS_CONTEXT, "BLOB reference header overflow");
581
582
			new_size = head_size + ref_size * max_refs;
583
584
			//Shift the metadata in the header
585
			if (CS_GET_DISK_2(ptr.rp_head->rb_mdata_size_2)) {
586
				uint16_t  mdata_size, mdata_offset, alias_offset, shift;
587
				
588
				shift = new_size - head_size;
589
				mdata_size = CS_GET_DISK_2(ptr.rp_head->rb_mdata_size_2);
590
				mdata_offset = CS_GET_DISK_2(ptr.rp_head->rb_mdata_offset_2);
591
				alias_offset = CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2);
592
				
593
				memmove(ptr.rp_chars + mdata_offset + shift, ptr.rp_chars + mdata_offset, shift);
594
				memset(ptr.rp_chars + mdata_offset, 0, shift);
595
				mdata_offset += shift;
596
				alias_offset += shift;
597
				
598
				CS_SET_DISK_2(ptr.rp_head->rb_mdata_offset_2, mdata_offset);
599
				CS_SET_DISK_2(ptr.rp_head->rb_alias_offset_2, alias_offset);
600
				
601
			} else
602
				memset(ptr.rp_chars + head_size, 0, new_size - head_size);
603
			
604
			new_head_size = new_size;
605
		}
606
		CS_SET_DISK_2(ptr.rp_head->rb_head_size_2, new_head_size);
607
		CS_SET_DISK_2(ptr.rp_head->rb_ref_count_2, ref_count + new_refs);
608
		ptr.rp_chars += myRepo->myRepoBlobHeadSize + ref_count * ref_size;
609
		
610
		if (!free_ref) {
611
			free_ref = ptr.rp_blob_ref;
612
			memset(free_ref, 0, ref_size);
613
			ptr.rp_chars += ref_size;
614
		}
615
616
		if (!tab_ref) {
617
			free2_ref = ptr.rp_blob_ref;
618
			memset(free2_ref, 0, ref_size);	
619
		}
620
		
621
		ref_count += new_refs;
622
	}
623
	else
624
		new_head_size = head_size;
625
626
	if (!tab_ref) {
627
		tab_ref = (MSRepoTableRefPtr) free2_ref;
628
629
		CS_SET_DISK_2(tab_ref->rr_type_2, MS_BLOB_TABLE_REF);
630
		CS_SET_DISK_4(tab_ref->tr_table_id_4, tab_id);
631
		CS_SET_DISK_6(tab_ref->tr_blob_id_6, blob_id);
632
	}
633
634
	size_t tab_idx;
635
636
	tab_idx = (((char *) tab_ref - otab->myOTBuffer) - myRepo->myRepoBlobHeadSize) / ref_size;
637
638
	CS_SET_DISK_2(free_ref->er_table_2, tab_idx+1);
639
	CS_SET_DISK_2(free_ref->er_col_index_2, col_index);
640
	CS_SET_DISK_8(free_ref->er_blob_ref_id_8, UNCOMMITTED(blob_ref_id));
641
642
	update_blob_header(otab, offset, blob_size, head_size, new_head_size);
643
#ifdef HAVE_ALIAS_SUPPORT
644
	if (reset_alias_index) 
645
		myRepo->myRepoDatabase->registerBlobAlias(myRepo->myRepoID, offset, blob_alias);
646
#endif
647
648
done:
649
	
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
650
	unlock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
651
	exit_();
652
}
653
654
void MSRepoFile::setBlobMetaData(MSOpenTable *otab, uint64_t offset, const char *meta_data, uint16_t meta_data_len, bool reset_alias, const char  *alias)
655
{
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
656
	CSMutex				*mylock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
657
	MSRepoPointersRec	ptr;
658
	size_t				read_size;
659
	uint16_t				new_head_size;
660
	uint64_t				blob_size;
661
	uint16_t				head_size, mdata_size, mdata_offset, alias_offset = 0;
662
	MSBlobHeadRec		blob;
663
	
664
	enter_();
665
	/* Lock the BLOB: */
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
666
	mylock = &myRepo->myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
667
	lock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
668
669
	/* Read the header: */
670
	if (read(&blob, offset, sizeof(MSBlobHeadRec), 0) < sizeof(MSBlobHeadRec)) {
671
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB header incomplete");
672
	}
673
674
	head_size = CS_GET_DISK_2(blob.rb_head_size_2);
675
676
	if (head_size > MS_OT_BUFFER_SIZE) {
677
		CSException::throwAssertion(CS_CONTEXT, "BLOB header overflow");
678
	}
679
	
680
	read_size = read(otab->myOTBuffer, offset, head_size, 0);
681
	ptr.rp_chars = otab->myOTBuffer;
682
	if (CS_GET_DISK_4(ptr.rp_head->rd_magic_4) != MS_BLOB_HEADER_MAGIC)
683
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
684
	if (read_size < myRepo->myRepoBlobHeadSize)
685
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB header incomplete");
686
	if (! IN_USE_BLOB_STATUS(CS_GET_DISK_1(ptr.rp_head->rb_status_1)))
687
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been deleted");
688
689
690
	blob_size = CS_GET_DISK_6(ptr.rp_head->rb_blob_repo_size_6);
691
	if (read_size < head_size) {
692
		/* This should not happen, because the file has been recovered,
693
		 * which should have already adjusted the head and blob
694
		 * size.
695
		 * If this happens then the file must have been truncated an the BLOB has been
696
		 * lost so we set the blob size to zero.
697
		 */
698
		head_size = read_size;
699
		blob_size = 0; 		
700
	}
701
	mdata_size = CS_GET_DISK_2(ptr.rp_head->rb_mdata_size_2);
702
703
	if ((meta_data_len < mdata_size) || MS_CAN_ADD_MDATA(ptr.rp_head, meta_data_len - mdata_size)) 
704
		new_head_size = head_size;
705
	else { // The header must be grown
706
707
		new_head_size = head_size + meta_data_len - mdata_size;
708
		if (new_head_size > MS_OT_BUFFER_SIZE)
709
			CSException::throwAssertion(CS_CONTEXT, "BLOB reference header overflow");
710
711
		memset(ptr.rp_chars + head_size, 0, new_head_size - head_size);		
712
	}	
713
				
714
	// Meta data is placed at the end of the header.
715
	if (meta_data_len)
716
		mdata_offset = new_head_size - meta_data_len;
717
	else
718
		mdata_offset = 0;
719
	mdata_size	= meta_data_len;
720
		
721
	
722
	CS_SET_DISK_2(ptr.rp_head->rb_mdata_size_2, mdata_size);
723
	CS_SET_DISK_2(ptr.rp_head->rb_mdata_offset_2, mdata_offset);
724
	
725
#ifdef HAVE_ALIAS_SUPPORT
1548.2.32 by Barry.Leslie at PrimeBase
Bug fix (sort of) for drop database when system tables are still open. The
726
	uint32_t alias_hash = INVALID_ALIAS_HASH;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
727
	if (alias) {
728
		alias_hash = CS_GET_DISK_4(ptr.rp_head->rb_alias_hash_4);
729
		alias_offset = CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2);
730
		if (reset_alias) {
731
			if (alias_offset)
732
				alias_hash = myRepo->myRepoDatabase->updateBlobAlias(myRepo->myRepoID, offset, alias_hash, alias);
733
			else {
734
				alias_hash = myRepo->myRepoDatabase->registerBlobAlias(myRepo->myRepoID, offset, alias);
735
			}
736
		}
737
		alias_offset = mdata_offset + (alias - meta_data);
738
		
739
	} else if (reset_alias && CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2)) {
740
		alias_offset = CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2);
741
		myRepo->myRepoDatabase->deleteBlobAlias(myRepo->myRepoID, offset, CS_GET_DISK_4(ptr.rp_head->rb_alias_hash_4));
742
		alias_offset = 0;
743
	}
744
#else
1897.2.3 by Brian Aker
Cast in order to avoid warning in ICC.
745
	uint32_t alias_hash = ((uint32_t)-1);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
746
	if (alias || reset_alias) {
747
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_IMPLEMENTED, "No BLOB alias support.");
748
	}
749
#endif
750
751
	CS_SET_DISK_2(ptr.rp_head->rb_alias_offset_2, alias_offset);
752
	CS_SET_DISK_4(ptr.rp_head->rb_alias_hash_4, alias_hash);
753
	
754
	memcpy(ptr.rp_chars + mdata_offset, meta_data, meta_data_len);
755
		
756
	update_blob_header(otab, offset, blob_size, head_size, new_head_size);
757
		
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
758
	unlock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
759
	exit_();
760
761
}
762
763
764
void MSRepoFile::releaseBlob(MSOpenTable *otab, uint64_t offset, uint16_t head_size, uint32_t tab_id, uint64_t blob_id, uint64_t blob_ref_id, uint32_t auth_code)
765
{
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
766
	CSMutex				*mylock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
767
	MSRepoPointersRec	ptr;
1548.2.20 by Barry.Leslie at PrimeBase
Code cleanup.
768
	uint32_t			table_ref_count = 0;
769
	uint32_t			size;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
770
	size_t				ref_size, ref_count, read_size;
771
	MSRepoTempRefPtr	temp_ref = NULL;
1548.2.20 by Barry.Leslie at PrimeBase
Code cleanup.
772
	uint16_t			tab_index = 0;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
773
	MSRepoTableRefPtr	tab_ref;
1548.2.20 by Barry.Leslie at PrimeBase
Code cleanup.
774
	uint16_t			alias_offset;
775
	uint32_t			alias_hash;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
776
777
	enter_();
778
	/* Lock the BLOB: */
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
779
	mylock = &myRepo->myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
780
	lock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
781
	/* Read the header: */
782
	ASSERT(head_size <= MS_OT_BUFFER_SIZE);
783
	read_size = read(otab->myOTBuffer, offset, head_size, 0);
784
	ptr.rp_chars = otab->myOTBuffer;
785
	if (CS_GET_DISK_4(ptr.rp_head->rd_magic_4) != MS_BLOB_HEADER_MAGIC)
786
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
787
	if (read_size < myRepo->myRepoBlobHeadSize) {
788
		removeBlob(otab, tab_id, blob_id, offset, auth_code);
789
		goto exit;
790
	}
791
	if ((! IN_USE_BLOB_STATUS(CS_GET_DISK_1(ptr.rp_head->rb_status_1))) ||
792
		CS_GET_DISK_4(ptr.rp_bytes + myRepo->myRepoBlobHeadSize - 4) != auth_code) {
793
		removeBlob(otab, tab_id, blob_id, offset, auth_code);
794
		goto exit;
795
	}
796
	
797
	/* Assume that what is here is correct: */
798
	if (head_size != CS_GET_DISK_2(ptr.rp_head->rb_head_size_2)) {
799
		head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
800
		read_size = read(otab->myOTBuffer, offset, head_size, myRepo->myRepoBlobHeadSize);
801
	}
802
	head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
803
	if (read_size < head_size) {
804
		/* This should not happen, because the file has been recovered,
805
		 * which should have already adjusted the head and blob
806
		 * size.
807
		 * If this happens then the file must have been truncated an the BLOB has been
808
		 * lost so we set the blob size to zero.
809
		 */
810
		head_size = read_size;
811
	}
812
	ref_size = CS_GET_DISK_1(ptr.rp_head->rb_ref_size_1);
813
	ref_count = CS_GET_DISK_2(ptr.rp_head->rb_ref_count_2);
814
815
	alias_offset = CS_GET_DISK_2(ptr.rp_head->rb_alias_offset_2);
816
	alias_hash = CS_GET_DISK_4(ptr.rp_head->rb_alias_hash_4);
817
818
	size = head_size - myRepo->myRepoBlobHeadSize;
819
	if (size > ref_size * ref_count)
820
		size = ref_size * ref_count;
821
	ptr.rp_chars += myRepo->myRepoBlobHeadSize;
822
	while (size >= ref_size) {
823
		switch (CS_GET_DISK_2(ptr.rp_ref->rr_type_2)) {
824
			case MS_BLOB_FREE_REF:
825
			case MS_BLOB_TABLE_REF:
826
				break;
827
			case MS_BLOB_DELETE_REF: {
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
828
				uint32_t tabi;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
829
830
				tabi = CS_GET_DISK_2(ptr.rp_temp_ref->tp_del_ref_2);
831
				if (tabi && tabi < ref_count) {
832
					tabi--;
833
					tab_ref = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepo->myRepoBlobHeadSize + tabi * ref_size);
834
					if (CS_GET_DISK_4(tab_ref->tr_table_id_4) == tab_id &&
835
						CS_GET_DISK_6(tab_ref->tr_blob_id_6) == blob_id) {
836
						/* This is an old free, take it out. */
837
						// Barry: What happens to the record in the temp log associated with this ref
838
						// that is waiting to free the BLOB?
839
						// Answer: It will find that there is MS_BLOB_DELETE_REF record with the BLOB
840
						// or if there is one it will be for a different free in a different temp log
841
						// or with a different temp log offset.
842
						CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);
843
					}
844
				}
845
				break;
846
			}
847
			default:  // Must be a blob REF
848
				tab_ref = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepo->myRepoBlobHeadSize + (CS_GET_DISK_2(ptr.rp_blob_ref->er_table_2)-1) * ref_size);
849
				if (CS_GET_DISK_4(tab_ref->tr_table_id_4) == tab_id &&
850
					CS_GET_DISK_6(tab_ref->tr_blob_id_6) == blob_id) {
851
					if (COMMIT_MASK(CS_GET_DISK_8(ptr.rp_blob_ref->er_blob_ref_id_8)) ==  blob_ref_id) {
852
						/* Found the reference, remove it... */
853
						tab_index = CS_GET_DISK_2(ptr.rp_blob_ref->er_table_2)-1;
854
						temp_ref = ptr.rp_temp_ref;
855
						//temp_ref = (MSRepoTempRefPtr) tab_ref; // Set temp ref to the table ref so that it will be removed if there are no more references to it.
856
						CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);						
857
					}
858
					else
859
						table_ref_count++;
860
				}
861
				break;
862
		}
863
		ptr.rp_chars += ref_size;
864
		size -= ref_size;
865
	}
866
867
	// If the refernce was found and there are no 
868
	// table references then the BLOB can be scheduled for deletion.
869
	if ((!table_ref_count) && temp_ref) {
870
		uint32_t	log_id;
871
		uint32_t log_offset;
872
		uint32_t temp_time;
873
#ifdef HAVE_ALIAS_SUPPORT
874
		MSDiskAliasRec aliasDiskRec;
875
		MSDiskAliasPtr aliasDiskPtr = NULL;
876
		
877
		if (alias_offset) {
878
			CS_SET_DISK_4(aliasDiskRec.ar_repo_id_4, myRepo->myRepoID);	
879
			CS_SET_DISK_8(aliasDiskRec.ar_offset_8, offset);	
880
			CS_SET_DISK_4(aliasDiskRec.ar_hash_4, alias_hash);
881
			aliasDiskPtr = &aliasDiskRec;
882
		}
883
		
884
		myRepo->myRepoDatabase->queueForDeletion(otab, MS_TL_BLOB_REF, tab_id, blob_id, auth_code, &log_id, &log_offset, &temp_time, aliasDiskPtr);
885
#else
886
		myRepo->myRepoDatabase->queueForDeletion(otab, MS_TL_BLOB_REF, tab_id, blob_id, auth_code, &log_id, &log_offset, &temp_time);
887
#endif
888
		myRepo->myLastTempTime = temp_time;
889
		CS_SET_DISK_2(temp_ref->rr_type_2, MS_BLOB_DELETE_REF);
890
		CS_SET_DISK_2(temp_ref->tp_del_ref_2, tab_index+1);
891
		CS_SET_DISK_4(temp_ref->tp_log_id_4, log_id);
892
		CS_SET_DISK_4(temp_ref->tp_offset_4, log_offset);
893
		
894
		CS_SET_DISK_1(ptr.rp_head->rb_status_1, MS_BLOB_ALLOCATED); // The BLOB is allocated but no longer referenced
895
	}
896
	if (temp_ref) {
897
		/* The reason I do not write the header of the header, is because
898
		 * I want to handle the rb_last_access_4 being set at the
899
		 * same time!
900
		 */
901
		write(otab->myOTBuffer + MS_BLOB_STAT_OFFS, offset + MS_BLOB_STAT_OFFS, head_size - MS_BLOB_STAT_OFFS);
1548.2.7 by Barry.Leslie at PrimeBase
Fixed some problems with transactions and drizzle.
902
	} else if (PBMSDaemon::isDaemonState(PBMSDaemon::DaemonStartUp) == false) {
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
903
		char message[100];
904
		snprintf(message, 100, "BLOB reference not found: db_id: %"PRIu32", tab_id:%"PRIu32", blob_ref_id: %"PRIu64"\n", myRepo->myRepoDatabase->myDatabaseID, tab_id, blob_ref_id);
905
		/* The reference already exists so there is nothing to do... */
906
		self->myException.log(self, message);
907
	}
908
909
	exit:
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
910
	unlock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
911
	exit_();
912
}
913
914
void MSRepoFile::commitBlob(MSOpenTable *otab, uint64_t offset, uint16_t head_size, uint32_t tab_id, uint64_t blob_id, uint64_t blob_ref_id, uint32_t auth_code)
915
{
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
916
	CSMutex				*mylock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
917
	MSRepoPointersRec	ptr;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
918
	uint32_t				size;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
919
	size_t				ref_size, ref_count, read_size;
920
	MSRepoTableRefPtr	tab_ref;
921
922
	enter_();
923
	/* Lock the BLOB: */
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
924
	mylock = &myRepo->myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
925
	lock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
926
	/* Read the header: */
927
	ASSERT(head_size <= MS_OT_BUFFER_SIZE);
928
	read_size = read(otab->myOTBuffer, offset, head_size, 0);
929
	ptr.rp_chars = otab->myOTBuffer;
930
	if (CS_GET_DISK_4(ptr.rp_head->rd_magic_4) != MS_BLOB_HEADER_MAGIC)
931
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
932
933
934
	if (read_size < myRepo->myRepoBlobHeadSize)
935
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB header incomplete");
936
	if ( ! IN_USE_BLOB_STATUS(CS_GET_DISK_1(ptr.rp_head->rb_status_1)))
937
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been deleted");
938
	if (auth_code && CS_GET_DISK_4(ptr.rp_bytes + myRepo->myRepoBlobHeadSize - 4) != auth_code)
939
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB data does not match reference");
940
941
	
942
	/* Assume that what is here is correct: */
943
	if (head_size != CS_GET_DISK_2(ptr.rp_head->rb_head_size_2)) {
944
		head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
945
		read_size = read(otab->myOTBuffer, offset, head_size, myRepo->myRepoBlobHeadSize);
946
	}
947
	
948
	head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
949
	if (read_size < head_size) {
950
		/* This should not happen, because the file has been recovered,
951
		 * which should have already adjusted the head and blob
952
		 * size.
953
		 * If this happens then the file must have been truncated an the BLOB has been
954
		 * lost so we set the blob size to zero.
955
		 */
956
		head_size = read_size;
957
	}
958
	ref_size = CS_GET_DISK_1(ptr.rp_head->rb_ref_size_1);
959
	ref_count = CS_GET_DISK_2(ptr.rp_head->rb_ref_count_2);
960
961
	size = head_size - myRepo->myRepoBlobHeadSize;
962
	if (size > ref_size * ref_count)
963
		size = ref_size * ref_count;
964
	ptr.rp_chars += myRepo->myRepoBlobHeadSize;
965
	while (size >= ref_size) {
966
		switch (CS_GET_DISK_2(ptr.rp_ref->rr_type_2)) {
967
			case MS_BLOB_FREE_REF:
968
			case MS_BLOB_TABLE_REF:
969
				break;
970
			case MS_BLOB_DELETE_REF: {
971
				break;
972
			}
973
			default:  // Must be a blob REF
974
				tab_ref = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepo->myRepoBlobHeadSize + (CS_GET_DISK_2(ptr.rp_blob_ref->er_table_2)-1) * ref_size);
975
				if (CS_GET_DISK_4(tab_ref->tr_table_id_4) == tab_id &&
976
					CS_GET_DISK_6(tab_ref->tr_blob_id_6) == blob_id) {
977
					uint64_t ref_id = CS_GET_DISK_8(ptr.rp_blob_ref->er_blob_ref_id_8);
978
					if (COMMIT_MASK(ref_id) ==  blob_ref_id) {
979
						/* Found the reference, mark it as committed... */
980
						CS_SET_DISK_8(ptr.rp_blob_ref->er_blob_ref_id_8, blob_ref_id);
981
						offset += 	(ptr.rp_chars - otab->myOTBuffer) + offsetof(MSRepoBlobRefRec, er_blob_ref_id_8);
982
						write(&(ptr.rp_blob_ref->er_blob_ref_id_8), offset, 8);					
983
						goto exit;
984
					}
985
				}
986
				break;
987
		}
988
		ptr.rp_chars += ref_size;
989
		size -= ref_size;
990
	}
991
1548.2.7 by Barry.Leslie at PrimeBase
Fixed some problems with transactions and drizzle.
992
	if (PBMSDaemon::isDaemonState(PBMSDaemon::DaemonStartUp) == false) {
993
		char message[100];
994
		snprintf(message, 100, "BLOB reference not found: db_id: %"PRIu32", tab_id:%"PRIu32", blob_ref_id: %"PRIu64"\n", myRepo->myRepoDatabase->myDatabaseID, tab_id, blob_ref_id);
995
		self->myException.log(self, message);
996
	}
997
	
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
998
	exit:
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
999
	unlock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1000
	exit_();
1001
}
1002
1003
void MSRepoFile::realFreeBlob(MSOpenTable *otab, char *buffer, uint32_t auth_code, uint64_t offset, uint16_t head_size, uint64_t blob_size, size_t ref_size)
1004
{
1005
	uint32_t				tab_id;
1006
	uint64_t				blob_id;
1007
	size_t				size;
1008
	MSRepoPointersRec	ptr;
1009
	enter_();
1010
	
1011
	ptr.rp_chars = buffer;
1012
	
1013
	if (BLOB_IN_CLOUD(CS_GET_DISK_1(ptr.rp_head->rb_storage_type_1))) {
1014
		CloudKeyRec key;
1015
		getBlobKey(ptr.rp_head, &key);
1016
		if (!myRepo->myRepoDatabase->myBlobCloud)
1017
			CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Deleting cloud BLOB without cloud.");
1018
			
1019
		myRepo->myRepoDatabase->myBlobCloud->cl_deleteData(&key); 
1020
	}
1021
		
1022
#ifdef HAVE_ALIAS_SUPPORT
1023
	uint32_t				alias_hash;
1024
	alias_hash = CS_GET_DISK_4(ptr.rp_head->rb_alias_hash_4);
1025
	if (alias_hash != INVALID_ALIAS_HASH)
1026
		myRepo->myRepoDatabase->deleteBlobAlias(myRepo->myRepoID, offset, alias_hash);
1027
#endif
1028
1029
	// Assuming the BLOB is still locked:
1030
	CS_SET_DISK_1(ptr.rp_head->rb_status_1, MS_BLOB_DELETED);
1031
	write(ptr.rp_chars + MS_BLOB_STAT_OFFS, offset + MS_BLOB_STAT_OFFS, head_size - MS_BLOB_STAT_OFFS);
1032
1033
	/* Update garbage count: */
1034
	updateGarbage(head_size + blob_size);
1035
1036
	/* Remove all table references (should not be any)! */
1037
	size = head_size - myRepo->myRepoBlobHeadSize;
1038
	ptr.rp_chars += myRepo->myRepoBlobHeadSize;
1039
	while (size >= ref_size) {
1040
		if (CS_GET_DISK_2(ptr.rp_ref->rr_type_2) == MS_BLOB_TABLE_REF) {
1041
			tab_id = CS_GET_DISK_4(ptr.rp_tab_ref->tr_table_id_4);
1042
			blob_id = CS_GET_DISK_6(ptr.rp_tab_ref->tr_blob_id_6);				
1043
			removeBlob(otab, tab_id, blob_id, offset, auth_code);
1044
		}
1045
		ptr.rp_chars += ref_size;
1046
		size -= ref_size;
1047
	}
1048
	exit_();
1049
}
1050
1051
/* This function will free the BLOB reference, if the record is invalid. */
1052
void MSRepoFile::freeTableReference(MSOpenTable *otab, uint64_t offset, uint16_t head_size, uint32_t tab_id, uint64_t blob_id, uint32_t auth_code)
1053
{
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1054
	CSMutex				*mylock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1055
	MSRepoPointersRec	ptr;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1056
	uint32_t				blob_ref_count = 0;
1057
	uint32_t				table_ref_count = 0;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1058
	bool				modified = false;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1059
	uint32_t				size;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1060
	size_t				ref_size, ref_count, read_size;
1061
	MSRepoTableRefPtr	tab_ref = NULL;
1062
	uint64_t				blob_size;
1063
1064
	enter_();
1065
	/* Lock the BLOB: */
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1066
	mylock = &myRepo->myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
1067
	lock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1068
	/* Read the header: */
1069
	ASSERT(head_size <= MS_OT_BUFFER_SIZE);
1070
	read_size = read(otab->myOTBuffer, offset, head_size, 0);
1071
	ptr.rp_chars = otab->myOTBuffer;
1072
	if (CS_GET_DISK_4(ptr.rp_head->rd_magic_4) != MS_BLOB_HEADER_MAGIC)
1073
		CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "Invalid BLOB identifier");
1074
	if (read_size < myRepo->myRepoBlobHeadSize) {
1075
		removeBlob(otab, tab_id, blob_id, offset, auth_code);
1076
		goto exit;
1077
	}
1078
	if ((! IN_USE_BLOB_STATUS(CS_GET_DISK_1(ptr.rp_head->rb_status_1))) ||
1079
		CS_GET_DISK_4(ptr.rp_bytes + myRepo->myRepoBlobHeadSize - 4) != auth_code) {
1080
		removeBlob(otab, tab_id, blob_id, offset, auth_code);
1081
		goto exit;
1082
	}
1083
	
1084
	/* Assume that what is here is correct: */
1085
	if (head_size != CS_GET_DISK_2(ptr.rp_head->rb_head_size_2)) {
1086
		head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
1087
		read_size = read(otab->myOTBuffer, offset, head_size, myRepo->myRepoBlobHeadSize);
1088
	}
1089
	head_size = CS_GET_DISK_2(ptr.rp_head->rb_head_size_2);
1090
	blob_size = CS_GET_DISK_6(ptr.rp_head->rb_blob_repo_size_6);
1091
	if (read_size < head_size) {
1092
		/* This should not happen, because the file has been recovered,
1093
		 * which should have already adjusted the head and blob
1094
		 * size.
1095
		 * If this happens then the file must have been truncated an the BLOB has been
1096
		 * lost so we set the blob size to zero.
1097
		 */
1098
		head_size = read_size;
1099
		blob_size = 0; 
1100
		
1101
	}
1102
	ref_size = CS_GET_DISK_1(ptr.rp_head->rb_ref_size_1);
1103
	ref_count = CS_GET_DISK_2(ptr.rp_head->rb_ref_count_2);
1104
	size = head_size - myRepo->myRepoBlobHeadSize;
1105
	if (size > ref_size * ref_count)
1106
		size = ref_size * ref_count;
1107
	ptr.rp_chars += myRepo->myRepoBlobHeadSize;
1108
	while (size >= ref_size) {
1109
		switch (CS_GET_DISK_2(ptr.rp_ref->rr_type_2)) {
1110
			case MS_BLOB_FREE_REF:
1111
				break;
1112
			case MS_BLOB_TABLE_REF:
1113
				if (CS_GET_DISK_4(ptr.rp_tab_ref->tr_table_id_4) == tab_id &&
1114
					CS_GET_DISK_6(ptr.rp_tab_ref->tr_blob_id_6) == blob_id)
1115
					tab_ref = ptr.rp_tab_ref;
1116
				break;
1117
			case MS_BLOB_DELETE_REF:
1118
			break;
1119
			default:
1120
				MSRepoTableRefPtr tr;
1121
1122
				tr = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepo->myRepoBlobHeadSize + (CS_GET_DISK_2(ptr.rp_blob_ref->er_table_2)-1) * ref_size);
1123
				if (CS_GET_DISK_2(tr->rr_type_2) == MS_BLOB_TABLE_REF) {
1124
					/* I am deleting all references of a table. So I am here to
1125
					 * also delete the blob references that refer to the
1126
					 * table reference!!!
1127
					 */
1128
					if (CS_GET_DISK_4(tr->tr_table_id_4) == tab_id && CS_GET_DISK_6(tr->tr_blob_id_6) == blob_id) {
1129
						/* Free the blob reference: */
1130
						CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);
1131
						modified = true;
1132
					}
1133
					else
1134
						blob_ref_count++;
1135
				
1136
				}
1137
				break;
1138
		}
1139
		ptr.rp_chars += ref_size;
1140
		size -= ref_size;
1141
	}
1142
1143
	if (!table_ref_count && tab_ref) {
1144
		CS_SET_DISK_2(tab_ref->rr_type_2, MS_BLOB_FREE_REF);
1145
		modified = true;
1146
	}
1147
	
1148
	
1149
	if (!blob_ref_count) {
1150
		realFreeBlob(otab, otab->myOTBuffer, auth_code, offset, head_size, blob_size, ref_size);
1151
	} else if (modified)
1152
		/* The reason I do not write the header of the header, is because
1153
		 * I want to handle the rb_last_access_4 being set at the
1154
		 * same time!
1155
		 */
1156
		write(otab->myOTBuffer + MS_BLOB_STAT_OFFS, offset + MS_BLOB_STAT_OFFS, head_size - MS_BLOB_STAT_OFFS);
1157
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1158
	unlock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1159
1160
	if (!table_ref_count || !tab_ref)
1161
		/* Free the table reference, if there are no more
1162
		 * blob references, reference the table reference,
1163
		 * or if the table reference was not found in the
1164
		 * BLOB at all!
1165
		 */
1166
		removeBlob(otab, tab_id, blob_id, offset, auth_code);
1167
1168
	exit_();
1169
1170
	exit:
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1171
	unlock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1172
	exit_();
1173
}
1174
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1175
void MSRepoFile::checkBlob(CSStringBuffer *buffer, uint64_t offset, uint32_t auth_code, uint32_t temp_log_id, uint32_t temp_log_offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1176
{
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1177
	CSMutex				*mylock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1178
	MSBlobHeadRec		blob;
1179
	MSRepoPointersRec	ptr;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1180
	uint32_t				blob_ref_count = 0;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1181
	bool				modified = false;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1182
	uint32_t				size;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1183
	size_t				ref_size, ref_count, read_size;
1184
	uint8_t				status;
1185
	uint16_t				head_size;
1186
	uint64_t				blob_size;
1187
	MSRepoTempRefPtr	my_ref = NULL;
1188
	uint16_t				ref_type = MS_BLOB_FREE_REF;
1189
	enter_();
1190
	
1191
	/* Lock the BLOB: */
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1192
	mylock = &myRepo->myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
1193
	lock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1194
1195
	/* Read the head of the header: */
1196
	if (read(&blob, offset, sizeof(MSBlobHeadRec), 0) < sizeof(MSBlobHeadRec)) 
1197
		goto exit;
1198
1199
	// Because the temp log will be replayed from the start when the server
1200
	// is restarted it is likely that it will have references to BLOBs that
1201
	// no longer exist. So it is not an error if the BLOB ref doesn't point to
1202
	// a valid BLOB. 
1203
	//
1204
	// At some point this should probably be rethought because you cannot
1205
	// tell the diference between a bad ref because of old data and a bad 
1206
	// ref because of a BUG.
1207
	if (CS_GET_DISK_4(blob.rd_magic_4) != MS_BLOB_HEADER_MAGIC) 
1208
		goto exit;
1209
	
1210
	head_size = CS_GET_DISK_2(blob.rb_head_size_2);
1211
	blob_size = CS_GET_DISK_6(blob.rb_blob_repo_size_6);
1212
	ref_size = CS_GET_DISK_1(blob.rb_ref_size_1);
1213
	ref_count = CS_GET_DISK_2(blob.rb_ref_count_2);
1214
	status = CS_GET_DISK_1(blob.rb_status_1);
1215
	if (! IN_USE_BLOB_STATUS(status))
1216
		goto exit;
1217
1218
	/* Read the entire header: */
1219
	buffer->setLength(head_size);
1220
	ptr.rp_chars = buffer->getBuffer(0);
1221
	read_size = read(ptr.rp_chars, offset, head_size, 0);
1222
	if (read_size < myRepo->myRepoBlobHeadSize)
1223
		goto exit;
1224
	if (CS_GET_DISK_4(ptr.rp_bytes + myRepo->myRepoBlobHeadSize - 4) != auth_code)
1225
		goto exit;
1226
	if (read_size < head_size) {
1227
		/* This should not happen, because the file has been recovered,
1228
		 * which should have already adjusted the head and blob
1229
		 * size.
1230
		 * If this happens then the file must have been truncated an the BLOB has been
1231
		 * lost so we set the blob size to zero.
1232
		 */
1233
		head_size = read_size;
1234
		blob_size = 0; 
1235
	}
1236
	size = head_size - myRepo->myRepoBlobHeadSize;
1237
	if (size > ref_size * ref_count)
1238
		size = ref_size * ref_count;
1239
1240
	
1241
	/* Search through all references: */
1242
	ptr.rp_chars += myRepo->myRepoBlobHeadSize;
1243
	while (size >= ref_size) {
1244
		switch (CS_GET_DISK_2(ptr.rp_ref->rr_type_2)) {
1245
			case MS_BLOB_FREE_REF:
1246
				break;
1247
			case MS_BLOB_TABLE_REF:
1248
				break;
1249
			case MS_BLOB_DELETE_REF:
1250
				if (CS_GET_DISK_4(ptr.rp_temp_ref->tp_log_id_4) == temp_log_id &&
1251
					CS_GET_DISK_4(ptr.rp_temp_ref->tp_offset_4) == temp_log_offset) {
1252
					ref_type = CS_GET_DISK_2(ptr.rp_ref->rr_type_2);
1253
					my_ref = ptr.rp_temp_ref;
1254
					CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);
1255
					modified = true;
1256
				}
1257
				break;
1258
			default:
1259
				MSRepoTableRefPtr	tr;
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1260
				uint32_t				tabi;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1261
1262
				tabi = CS_GET_DISK_2(ptr.rp_blob_ref->er_table_2);
1263
				if (tabi < ref_count) {
1264
					tr = (MSRepoTableRefPtr) (buffer->getBuffer(0) + myRepo->myRepoBlobHeadSize + (tabi-1) * ref_size);
1265
					if (CS_GET_DISK_2(tr->rr_type_2) == MS_BLOB_TABLE_REF)
1266
						blob_ref_count++;
1267
				}
1268
				break;
1269
		}
1270
		ptr.rp_chars += ref_size;
1271
		size -= ref_size;
1272
	}
1273
1274
	if ((ref_type == (uint16_t)MS_BLOB_DELETE_REF) && !blob_ref_count) {
1275
		realFreeBlob(NULL, buffer->getBuffer(0), auth_code, offset, head_size, blob_size, ref_size);
1276
	}
1277
	
1278
	exit:
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1279
	unlock_(mylock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1280
	exit_();
1281
}
1282
1283
void MSRepoFile::returnToPool()
1284
{
1285
	myRepo->myRepoDatabase->returnRepoFileToPool(this);
1286
}
1287
1288
void MSRepoFile::removeBlob(MSOpenTable *otab, uint32_t tab_id, uint64_t blob_id, uint64_t offset, uint32_t auth_code)
1289
{
1290
	enter_();
1291
	if (otab && otab->getDBTable()->myTableID == tab_id)
1292
		otab->getDBTable()->freeBlobHandle(otab, blob_id, myRepo->myRepoID, offset, auth_code);
1293
	else {
1294
		MSOpenTable *tmp_otab;
1295
1296
		if ((tmp_otab = MSTableList::getOpenTableByID(myRepo->myRepoDatabase->myDatabaseID, tab_id))) {
1297
			frompool_(tmp_otab);
1298
			tmp_otab->getDBTable()->freeBlobHandle(tmp_otab, blob_id, myRepo->myRepoID, offset, auth_code);
1299
			backtopool_(tmp_otab);
1300
		}
1301
	}
1302
	exit_();
1303
}
1304
1305
MSRepoFile *MSRepoFile::newRepoFile(MSRepository *repo, CSPath *path)
1306
{
1307
	MSRepoFile *f;
1308
	
1309
	if (!(f = new MSRepoFile())) {
1310
		path->release();
1311
		CSException::throwOSError(CS_CONTEXT, ENOMEM);
1312
	}
1313
	f->myRepo = repo;
1314
	f->myFilePath = path;
1315
	return f;
1316
}
1317
1318
/*
1319
 * ---------------------------------------------------------------
1320
 * REPOSITORY
1321
 */
1322
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1323
MSRepository::MSRepository(uint32_t id, MSDatabase *db, off64_t file_size):
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1324
CSSharedRefObject(),
1325
myRepoID(id),
1326
myRepoFileSize(file_size),
1327
myRepoLockState(REPO_UNLOCKED),
1328
isRemovingFP(false),
1329
myRepoDatabase(db),
1330
myGarbageCount(0),
1331
myRepoHeadSize(0),
1332
myRepoDefRefSize(0),
1333
myRepoBlobHeadSize(0),
1334
myRecoveryOffset(0),
1335
myLastTempTime(0),
1336
myLastAccessTime(0),
1337
myLastCreateTime(0),
1338
myLastRefTime(0),
1339
mustBeDeleted(false),
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1340
myRepoXLock(false),
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1341
iFilePool(NULL)
1342
{
1343
}
1344
1345
MSRepository::~MSRepository()
1346
{
1347
	CSPath *path = NULL;
1348
1349
	enter_();
1350
	if (mustBeDeleted) {
1351
		path = getRepoFilePath();
1352
		push_(path);
1353
	}
1354
1355
	isRemovingFP = true;
1356
	removeRepoFilesNotInUse();
1357
	/* With this, I also delete those that are in use!: */
1358
	iPoolFiles.clear();
1359
1360
	if (path) {
1361
		path->removeFile();
1362
		release_(path);
1363
	}
1364
	exit_();
1365
}
1366
1367
void MSRepository::openRepoFileForWriting(MSOpenTable *otab)
1368
{
1369
	if (!otab->myWriteRepoFile)
1370
		otab->myWriteRepoFile = openRepoFile();
1371
}
1372
1373
uint64_t MSRepository::receiveBlob(MSOpenTable *otab, uint16_t head_size, uint64_t blob_size, Md5Digest *checksum, CSInputStream *stream)
1374
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1375
	off64_t	offset;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1376
	size_t	tfer;
1377
1378
	enter_();
1379
		
1380
	offset = myRepoFileSize;
1381
1382
	offset += head_size;
1383
	
1384
	ASSERT(myRepoDatabase->myBlobType == MS_STANDARD_STORAGE);
1385
	if (stream) {
1386
		CSMd5 md5;
1387
		push_(stream);
1388
		md5.md5_init();
1389
		while (blob_size > 0) {
1390
			if (blob_size <=  MS_OT_BUFFER_SIZE)
1391
				tfer = (size_t) blob_size;
1392
			else
1393
				tfer = MS_OT_BUFFER_SIZE;
1394
			tfer = stream->read(otab->myOTBuffer, tfer);
1395
			if (!tfer)
1396
				CSException::throwOSError(CS_CONTEXT, EPIPE);
1397
			if (checksum) md5.md5_append((const u_char *)(otab->myOTBuffer), tfer);
1398
			otab->myWriteRepoFile->write(otab->myOTBuffer, offset, tfer);
1399
			offset += (uint64_t) tfer;
1400
			blob_size -= (uint64_t) tfer;
1401
		}
1841.1.3 by Barry.Leslie at PrimeBase
Merged changes from lp:pbms. These changes should remove any danger
1402
		if (checksum) md5.md5_get_digest(checksum);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1403
		release_(stream);
1404
	} else {
1405
		// Write 1 byte to the end to reserver the space.
1406
		otab->myWriteRepoFile->write("x" , offset + blob_size -1, 1);
1407
	}
1408
1409
	return_( myRepoFileSize);
1410
}
1411
1412
// copyBlob() copies the BLOB and its header.
1413
uint64_t MSRepository::copyBlob(MSOpenTable *otab, uint64_t size, CSInputStream *stream)
1414
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1415
	off64_t	offset = myRepoFileSize;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1416
	size_t	tfer;
1417
1418
	while (size > 0) {
1419
		if (size <= MS_OT_BUFFER_SIZE)
1420
			tfer = (size_t) size;
1421
		else
1422
			tfer = MS_OT_BUFFER_SIZE;
1423
		tfer = stream->read(otab->myOTBuffer, tfer);
1424
		if (!tfer)
1425
			CSException::throwOSError(CS_CONTEXT, EPIPE);
1426
		otab->myWriteRepoFile->write(otab->myOTBuffer, offset, tfer);
1427
		offset += (uint64_t) tfer;
1428
		size -= (uint64_t) tfer;
1429
	}
1430
	
1431
	return myRepoFileSize;
1432
}
1433
1434
void MSRepository::writeBlobHead(MSOpenTable *otab, uint64_t offset, uint8_t ref_size, uint16_t head_size, uint64_t blob_size, Md5Digest *checksum, char *metadata, uint16_t metadata_size, uint64_t blob_id, uint32_t auth_code, uint32_t log_id, uint32_t log_offset, uint8_t blob_type, CloudKeyPtr cloud_key)
1435
{
1436
	MSBlobHeadPtr		blob ;
1437
	MSRepoTableRefPtr	tab_ref;
1438
	MSRepoTempRefPtr	temp_ref;
1439
	time_t				now;
1440
	uint16_t				tab_idx, max_ref_count = (head_size - myRepoBlobHeadSize - metadata_size) / ref_size;
1441
	size_t				size;
1442
	
1443
	if (max_ref_count > MS_REPO_MIN_REF_COUNT)
1444
		max_ref_count = MS_REPO_MIN_REF_COUNT;
1445
		
1446
	ASSERT(max_ref_count > 1);
1447
	
1448
	if (blob_type == MS_CLOUD_STORAGE) 
1449
		now = cloud_key->creation_time;
1450
	else
1451
		now = time(NULL);
1452
	
1453
	blob = (MSBlobHeadPtr) otab->myOTBuffer;
1454
	CS_SET_DISK_4(blob->rb_last_access_4, now);
1455
	CS_SET_DISK_4(blob->rb_mod_time_4, now);
1456
	CS_SET_DISK_4(blob->rb_access_count_4, 0);
1457
	CS_SET_DISK_4(blob->rb_backup_id_4, 0);
1458
	CS_SET_DISK_4(blob->rb_create_time_4, now);
1459
	CS_SET_DISK_4(blob->rd_magic_4, MS_BLOB_HEADER_MAGIC);
1460
	CS_SET_DISK_2(blob->rb_head_size_2, head_size);
1461
	CS_SET_DISK_6(blob->rb_blob_data_size_6, blob_size);
1462
	CS_SET_DISK_1(blob->rb_status_1, MS_BLOB_ALLOCATED);
1463
	CS_SET_DISK_1(blob->rb_ref_size_1, ref_size);
1464
	CS_SET_DISK_2(blob->rb_ref_count_2, max_ref_count);
1465
	CS_SET_DISK_4(blob->rb_last_ref_4, 0);
1466
	CS_SET_DISK_4(otab->myOTBuffer + myRepoBlobHeadSize - 4, auth_code);
1467
	if (checksum)
1468
		memcpy(&(blob->rb_blob_checksum_md5d), checksum, sizeof(Md5Digest));
1469
1470
	CS_SET_DISK_2(blob->rb_mdata_size_2, metadata_size);
1471
	if (metadata_size) {
1472
		uint16_t metadata_offset = head_size - metadata_size;
1473
		
1474
		CS_SET_DISK_2(blob->rb_mdata_offset_2, metadata_offset);
1475
		memcpy(otab->myOTBuffer + metadata_offset, metadata, metadata_size);
1476
		
1477
#ifdef HAVE_ALIAS_SUPPORT
1478
		MetaData md;	
1479
		md.use_data(metadata, metadata_size);
1480
		const char *alias;	
1481
		alias = md.findAlias();
1482
		if (alias) {
1483
			uint32_t alias_hash;
1484
			uint16_t alias_offset = metadata_offset + (uint16_t) (alias - metadata);
1485
			CS_SET_DISK_2(blob->rb_alias_offset_2, alias_offset);
1486
			alias_hash = myRepoDatabase->registerBlobAlias(myRepoID, offset, alias);
1487
			CS_SET_DISK_4(blob->rb_alias_hash_4, alias_hash);
1488
		} else {
1489
			CS_SET_DISK_2(blob->rb_alias_offset_2, 0);
1490
		}
1491
#else
1492
		CS_SET_DISK_2(blob->rb_alias_offset_2, 0);
1493
#endif
1494
		
1495
	} else {
1496
		CS_SET_DISK_2(blob->rb_mdata_offset_2, 0);
1497
		CS_SET_DISK_2(blob->rb_alias_offset_2, 0);
1498
	}
1499
	
1500
1501
	if (blob_id) {
1502
		tab_ref = (MSRepoTableRefPtr) (otab->myOTBuffer + myRepoBlobHeadSize);
1503
		CS_SET_DISK_2(tab_ref->rr_type_2, MS_BLOB_TABLE_REF);
1504
		CS_SET_DISK_4(tab_ref->tr_table_id_4, otab->getDBTable()->myTableID);
1505
		CS_SET_DISK_6(tab_ref->tr_blob_id_6, blob_id);
1506
		temp_ref = (MSRepoTempRefPtr) (otab->myOTBuffer + myRepoBlobHeadSize + ref_size);
1507
		tab_idx = 1;  // This is the index of the blob table ref in the repository record.
1508
		size = myRepoBlobHeadSize + ref_size + ref_size;
1509
	}
1510
	else {
1511
		temp_ref = (MSRepoTempRefPtr) (otab->myOTBuffer + myRepoBlobHeadSize);
1512
		tab_idx = INVALID_INDEX;  // Means not used
1513
		size = myRepoBlobHeadSize + ref_size;
1514
	}
1515
1516
	CS_SET_DISK_2(temp_ref->rr_type_2, MS_BLOB_DELETE_REF);
1517
	CS_SET_DISK_2(temp_ref->tp_del_ref_2, tab_idx);
1518
	CS_SET_DISK_4(temp_ref->tp_log_id_4, log_id);
1519
	CS_SET_DISK_4(temp_ref->tp_offset_4, log_offset);
1520
	
1521
	if (blob_type == MS_CLOUD_STORAGE) { // The data is stored in the cloud and not in the repository.
1522
		CS_SET_DISK_4(blob->rb_s3_key_id_4, cloud_key->ref_index);
1523
		CS_SET_DISK_4(blob->rb_s3_cloud_ref_4, cloud_key->cloud_ref);
1524
		blob_size = 0; // The blob is not stored in the repository so the blob storage size in the repository is zero
1525
	}
1526
1527
	memset(otab->myOTBuffer + size, 0, head_size - size - metadata_size);
1528
	
1529
	CS_SET_DISK_1(blob->rb_storage_type_1, blob_type);
1530
	CS_SET_DISK_6(blob->rb_blob_repo_size_6, blob_size);
1531
	otab->myWriteRepoFile->write(blob, offset, head_size);
1532
	
1533
	setRepoFileSize(otab, offset + head_size + blob_size);
1534
}
1535
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1536
void MSRepository::setRepoFileSize(MSOpenTable *otab, off64_t offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1537
{
1538
	myRepoFileSize = offset;
1548.2.3 by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability.
1539
	if (myRepoFileSize >= PBMSParameters::getRepoThreshold()
1540
		/**/ || getGarbageLevel() >= PBMSParameters::getGarbageThreshold())
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1541
		otab->closeForWriting();
1542
}
1543
1544
void MSRepository::syncHead(MSRepoFile *fh)
1545
{
1546
	MSRepoHeadRec head;
1547
1548
	fh->sync();
1549
	myRecoveryOffset = myRepoFileSize;
1550
	CS_SET_DISK_8(head.rh_recovery_offset_8, myRecoveryOffset);
1551
	CS_SET_DISK_4(head.rh_last_temp_time_4, myLastTempTime);
1552
	CS_SET_DISK_4(head.rh_last_access_4, myLastAccessTime);
1553
	CS_SET_DISK_4(head.rh_create_time_4, myLastCreateTime);
1554
	CS_SET_DISK_4(head.rh_last_ref_4, myLastRefTime);
1555
1556
	fh->write(&head.rh_recovery_offset_8, offsetof(MSRepoHeadRec, rh_recovery_offset_8), 24);
1557
	fh->sync();
1558
}
1559
1560
MSRepoFile *MSRepository::openRepoFile()
1561
{
1562
	MSRepoFile	*fh;
1563
1564
	enter_();
1565
	fh = MSRepoFile::newRepoFile(this, getRepoFilePath());
1566
	push_(fh);
1567
	if (myRepoFileSize)
1568
		fh->open(CSFile::DEFAULT);
1569
	else
1570
		fh->open(CSFile::CREATE);
1571
	if (!myRepoHeadSize) {
1572
		MSRepoHeadRec	head;
1573
		MSBlobHeadRec	blob;
1574
		size_t			size;
1575
		int				status;
1576
		int				ref_size;
1548.2.20 by Barry.Leslie at PrimeBase
Code cleanup.
1577
		uint16_t		head_size;
1578
		uint64_t		blob_size;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1579
1580
		lock_(this);
1581
		/* Check again after locking: */
1582
		if (!myRepoHeadSize) {
1583
			if (fh->read(&head, 0, offsetof(MSRepoHeadRec, rh_reserved_4), 0) < offsetof(MSRepoHeadRec, rh_reserved_4)) {
1584
				CS_SET_DISK_4(head.rh_magic_4, MS_REPO_FILE_MAGIC);
1585
				CS_SET_DISK_2(head.rh_version_2, MS_REPO_FILE_VERSION);
1586
				CS_SET_DISK_2(head.rh_repo_head_size_2, MS_REPO_FILE_HEAD_SIZE);
1587
				CS_SET_DISK_2(head.rh_blob_head_size_2, sizeof(MSBlobHeadRec));
1588
				CS_SET_DISK_2(head.rh_def_ref_size_2, sizeof(MSRepoGenericRefRec));
1589
				CS_SET_DISK_8(head.rh_recovery_offset_8, MS_REPO_FILE_HEAD_SIZE);
1590
				CS_SET_DISK_8(head.rh_garbage_count_8, 0);
1591
				CS_SET_DISK_4(head.rh_last_temp_time_4, 0);
1592
				CS_SET_DISK_4(head.rh_last_access_4, 0);
1593
				CS_SET_DISK_4(head.rh_create_time_4, 0);
1594
				CS_SET_DISK_4(head.rh_last_ref_4, 0);
1595
				CS_SET_DISK_4(head.rh_reserved_4, 0);
1596
				fh->write(&head, 0, sizeof(MSRepoHeadRec));
1597
			}
1598
			
1599
			/* Check the file header: */
1600
			if (CS_GET_DISK_4(head.rh_magic_4) != MS_REPO_FILE_MAGIC)
1601
				CSException::throwFileError(CS_CONTEXT, fh->getPathString(), CS_ERR_BAD_HEADER_MAGIC);
1602
			if (CS_GET_DISK_2(head.rh_version_2) > MS_REPO_FILE_VERSION)
1603
				CSException::throwFileError(CS_CONTEXT, fh->getPathString(), CS_ERR_VERSION_TOO_NEW);
1604
1605
			/* Load the header details: */
1606
			myRepoHeadSize = CS_GET_DISK_2(head.rh_repo_head_size_2);
1607
			myRepoDefRefSize = CS_GET_DISK_2(head.rh_def_ref_size_2);
1608
			myRepoBlobHeadSize = CS_GET_DISK_2(head.rh_blob_head_size_2);
1609
			myRecoveryOffset = CS_GET_DISK_8(head.rh_recovery_offset_8);
1610
			myGarbageCount = CS_GET_DISK_8(head.rh_garbage_count_8);
1611
			myLastTempTime = CS_GET_DISK_4(head.rh_last_temp_time_4);
1612
			myLastAccessTime = CS_GET_DISK_4(head.rh_last_access_4);
1613
			myLastCreateTime = CS_GET_DISK_4(head.rh_create_time_4);
1614
			myLastRefTime = CS_GET_DISK_4(head.rh_last_ref_4);
1615
1616
			/* File size, cannot be less than header size: */
1617
			if (myRepoFileSize < myRepoHeadSize)
1618
				myRepoFileSize = myRepoHeadSize;
1619
1620
			ASSERT(myGarbageCount <= myRepoFileSize);
1621
1622
			/* Recover the file: */
1623
			while (myRecoveryOffset < myRepoFileSize) {
1624
				if ((size = fh->read(&blob, myRecoveryOffset, MS_MIN_BLOB_HEAD_SIZE, 0)) < MS_MIN_BLOB_HEAD_SIZE) {
1625
					if (size != 0) {
1626
						myRepoFileSize = myRecoveryOffset;
1627
						fh->setEOF(myRepoFileSize);
1628
					}
1629
					break;
1630
				}
1631
				uint16_t ref_count, mdata_size, mdata_offset;
1632
				
1633
				status = CS_GET_DISK_1(blob.rb_status_1);
1634
				ref_size = CS_GET_DISK_1(blob.rb_ref_size_1);
1635
				ref_count = CS_GET_DISK_2(blob.rb_ref_count_2);
1548.2.20 by Barry.Leslie at PrimeBase
Code cleanup.
1636
				head_size = CS_GET_DISK_2(blob.rb_head_size_2);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1637
				mdata_size = CS_GET_DISK_2(blob.rb_mdata_size_2);
1638
				mdata_offset = CS_GET_DISK_2(blob.rb_mdata_offset_2);
1639
				blob_size = CS_GET_DISK_6(blob.rb_blob_repo_size_6);
1640
				if ((CS_GET_DISK_4(blob.rd_magic_4) != MS_BLOB_HEADER_MAGIC) ||
1641
					(! IN_USE_BLOB_STATUS(status)) ||
1642
					head_size < (myRepoBlobHeadSize + ref_size * MS_REPO_MIN_REF_COUNT) ||
1643
					head_size < (mdata_offset + mdata_size) ||
1644
					((blob_size == 0) && (BLOB_IN_REPOSITORY(CS_GET_DISK_1(blob.rb_storage_type_1)))) ||
1645
					myRecoveryOffset + head_size + blob_size > myRepoFileSize) {
1646
					myRepoFileSize = myRecoveryOffset;
1647
					fh->setEOF(myRepoFileSize);
1648
					break;
1649
				}
1650
				myRecoveryOffset += head_size + blob_size;
1651
			}
1652
1653
			fh->sync();
1654
			myRecoveryOffset = myRepoFileSize;
1655
			CS_SET_DISK_8(head.rh_recovery_offset_8, myRecoveryOffset);
1656
			fh->write(&head, offsetof(MSRepoHeadRec, rh_recovery_offset_8), 8);
1657
			fh->sync();
1658
		}
1659
		unlock_(this);
1660
	}
1661
	pop_(fh);
1662
	return_(fh);
1663
}
1664
1665
void MSRepository::lockRepo(RepoLockState state)
1666
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1667
	CSMutex	*myLock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1668
	enter_();
1669
	
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1670
	myLock = &myRepoLock[0];
1671
	lock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1672
	
1673
	ASSERT(!myRepoXLock);
1674
	
1675
	myRepoLockState = state;
1676
	myRepoXLock = true;
1677
		
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1678
	unlock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1679
	exit_();
1680
}
1681
1682
void MSRepository::signalCompactor()
1683
{
1684
#ifndef MS_COMPACTOR_POLLS
1685
	if (!mustBeDeleted) {
1548.2.3 by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability.
1686
		if (getGarbageLevel() >= PBMSParameters::getGarbageThreshold()) {
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1687
			if (myRepoDatabase->myCompactorThread)
1688
				myRepoDatabase->myCompactorThread->wakeup();
1689
		}
1690
	}
1691
#endif
1692
}
1693
1694
void MSRepository::unlockRepo(RepoLockState state)
1695
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1696
	CSMutex	*myLock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1697
	enter_();
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1698
	myLock = &myRepoLock[0];
1699
	lock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1700
	
1701
	ASSERT(myRepoLockState & state);
1702
	
1703
	myRepoLockState &= ~state;
1704
	if (myRepoLockState == REPO_UNLOCKED) {
1705
		myRepoXLock = false;
1706
		signalCompactor();
1707
	}
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1708
	unlock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1709
	
1710
	exit_();
1711
}
1712
1713
// Repositories are not removed from the pool when 
1714
// scheduled for backup so the REPO_BACKUP flag is
1715
// not handled here.
1716
void MSRepository::returnToPool()
1717
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1718
	CSMutex	*myLock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1719
	enter_();
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1720
	myLock = &myRepoLock[0];
1721
	lock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1722
	this->myRepoLockState &= ~(REPO_COMPACTING | REPO_WRITE);
1723
	if ( this->myRepoLockState == REPO_UNLOCKED) {
1724
		myRepoXLock = false;
1725
		signalCompactor();
1726
	}
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1727
	unlock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1728
	
1729
	this->release();
1730
	exit_();
1731
}
1732
1733
void MSRepository::backupCompleted()
1734
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1735
	CSMutex	*myLock;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1736
	enter_();
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1737
	myLock = &myRepoLock[0];
1738
	lock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1739
	
1740
	
1741
	this->myRepoLockState &= ~REPO_BACKUP;
1742
	if ( this->myRepoLockState == REPO_UNLOCKED) {
1743
		myRepoXLock = false;
1744
		signalCompactor();
1745
	}
1746
		
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1747
	unlock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1748
	exit_();
1749
}
1750
1751
bool MSRepository::lockedForBackup() { return ((myRepoLockState & REPO_BACKUP) == REPO_BACKUP);}
1752
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1753
uint32_t MSRepository::initBackup()
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1754
{
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1755
	CSMutex	*myLock;
1756
	uint32_t state;
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1757
	enter_();
1758
	
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1759
	myLock = &myRepoLock[0];
1760
	lock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1761
	state = this->myRepoLockState;
1762
	this->myRepoLockState |= REPO_BACKUP;
1763
	if (this->myRepoLockState == REPO_BACKUP) 
1764
		this->myRepoXLock = true;
1765
		
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1766
	unlock_(myLock);
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1767
	return_(state);
1768
}
1769
1770
MSRepoFile *MSRepository::getRepoFile()
1771
{
1772
	MSRepoFile *file;
1773
1774
	if ((file = iFilePool)) {
1775
		iFilePool = file->nextFile;
1776
		file->nextFile = NULL;
1777
		file->isFileInUse = true;
1778
		file->retain();
1779
	}
1780
	return file;
1781
}
1782
1783
void MSRepository::addRepoFile(MSRepoFile *file)
1784
{
1785
	iPoolFiles.addFront(file);
1786
}
1787
1788
void MSRepository::removeRepoFile(MSRepoFile *file)
1789
{
1790
	iPoolFiles.remove(file);
1791
}
1792
1793
void MSRepository::returnRepoFile(MSRepoFile *file)
1794
{
1795
	file->isFileInUse = false;
1796
	file->nextFile = iFilePool;
1797
	iFilePool = file;
1798
}
1799
1800
bool MSRepository::removeRepoFilesNotInUse()
1801
{
1802
	MSRepoFile *file, *curr_file;
1803
1804
	iFilePool = NULL;
1805
	/* Remove all files that are not in use: */
1806
	if ((file = (MSRepoFile *) iPoolFiles.getBack())) {
1807
		do {
1808
			curr_file = file;
1809
			file = (MSRepoFile *) file->getNextLink();
1810
			if (!curr_file->isFileInUse)
1811
				iPoolFiles.remove(curr_file);
1812
		} while (file);
1813
	}
1814
	return iPoolFiles.getSize() == 0;
1815
}
1816
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1817
off64_t MSRepository::getRepoFileSize()
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1818
{
1819
	return myRepoFileSize;
1820
}
1821
1822
size_t MSRepository::getRepoHeadSize()
1823
{
1824
	return myRepoHeadSize;
1825
}
1826
1827
size_t MSRepository::getRepoBlobHeadSize()
1828
{
1829
	return myRepoBlobHeadSize;
1830
}
1831
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1832
CSMutex *MSRepository::getRepoLock(off64_t offset)
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1833
{
1834
	return &myRepoLock[offset % CS_REPO_REC_LOCK_COUNT];
1835
}
1836
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1837
uint32_t MSRepository::getRepoID()
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1838
{
1839
	return myRepoID;
1840
}
1841
1548.2.2 by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle.
1842
uint32_t MSRepository::getGarbageLevel()
1548.2.1 by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin.
1843
{
1844
	if (myRepoFileSize <= myRepoHeadSize)
1845
		return 0;
1846
	return myGarbageCount * 100 / (myRepoFileSize - myRepoHeadSize);
1847
}
1848
1849
CSPath *MSRepository::getRepoFilePath()
1850
{
1851
	char file_name[120];
1852
1853
	cs_strcpy(120, file_name, "bs-repository");
1854
	cs_add_dir_char(120, file_name);
1855
	cs_strcat(120, file_name, "repo-");
1856
	cs_strcat(120, file_name, myRepoID);
1857
	cs_strcat(120, file_name, ".bs");
1858
1859
	if (myRepoDatabase && myRepoDatabase->myDatabasePath) {
1860
		return CSPath::newPath(RETAIN(myRepoDatabase->myDatabasePath), file_name);
1861
	}
1862
	return NULL;
1863
}
1864