8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 06:43:04 +01:00

1) Reworked memory management in SORT. Now we're pools aware there.

2) Reworked error handling in SORT and its callers.
3) Replaced DLS+SortMem with the generic TempSpace class.
4) Replaced GDS temp file management with the TempFile class.
5) Various cleanup.
This commit is contained in:
dimitr 2006-05-31 08:53:00 +00:00
parent 52c314d7e2
commit 7cc12e8489
37 changed files with 1402 additions and 1697 deletions

View File

@ -187,6 +187,9 @@
<File
RelativePath="..\..\..\src\jrd\os\win32\path_utils.cpp">
</File>
<File
RelativePath="..\..\..\src\common\classes\TempFile.cpp">
</File>
<File
RelativePath="..\..\..\src\common\classes\timestamp.cpp">
</File>
@ -236,6 +239,9 @@
<File
RelativePath="..\..\..\src\common\classes\MetaName.h">
</File>
<File
RelativePath="..\..\..\src\common\classes\TempFile.h">
</File>
<File
RelativePath="..\..\..\src\common\classes\timestamp.h">
</File>

View File

@ -186,6 +186,9 @@
<File
RelativePath="..\..\..\src\jrd\os\win32\path_utils.cpp">
</File>
<File
RelativePath="..\..\..\src\common\classes\TempFile.cpp">
</File>
<File
RelativePath="..\..\..\src\common\classes\timestamp.cpp">
</File>
@ -232,6 +235,9 @@
<File
RelativePath="..\..\..\src\common\classes\MetaName.h">
</File>
<File
RelativePath="..\..\..\src\common\classes\TempFile.h">
</File>
<File
RelativePath="..\..\..\src\common\classes\timestamp.h">
</File>

View File

@ -168,9 +168,6 @@
<File
RelativePath="..\..\..\src\jrd\divorce.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\dls.cpp">
</File>
<File
RelativePath="..\..\..\gen\jrd\dpm.cpp">
</File>
@ -351,9 +348,6 @@
<File
RelativePath="..\..\..\src\jrd\sort.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\sort_mem.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\sqz.cpp">
</File>
@ -366,6 +360,9 @@
<File
RelativePath="..\..\..\src\jrd\sym.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\TempSpace.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\thd.cpp">
</File>
@ -499,9 +496,6 @@
<File
RelativePath="..\..\..\src\jrd\divorce.h">
</File>
<File
RelativePath="..\..\..\src\jrd\dls_proto.h">
</File>
<File
RelativePath="..\..\..\src\jrd\dmp_proto.h">
</File>
@ -958,6 +952,9 @@
<File
RelativePath="..\..\..\src\jrd\sym_proto.h">
</File>
<File
RelativePath="..\..\..\src\jrd\TempSpace.h">
</File>
<File
RelativePath="..\..\..\src\jrd\termtype.h">
</File>

View File

@ -168,9 +168,6 @@
<File
RelativePath="..\..\..\src\jrd\divorce.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\dls.cpp">
</File>
<File
RelativePath="..\..\..\gen\jrd\dpm.cpp">
</File>
@ -351,9 +348,6 @@
<File
RelativePath="..\..\..\src\jrd\sort.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\sort_mem.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\sqz.cpp">
</File>
@ -366,6 +360,9 @@
<File
RelativePath="..\..\..\src\jrd\sym.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\TempSpace.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\thd.cpp">
</File>
@ -499,9 +496,6 @@
<File
RelativePath="..\..\..\src\jrd\divorce.h">
</File>
<File
RelativePath="..\..\..\src\jrd\dls_proto.h">
</File>
<File
RelativePath="..\..\..\src\jrd\dmp_proto.h">
</File>
@ -958,6 +952,9 @@
<File
RelativePath="..\..\..\src\jrd\sym_proto.h">
</File>
<File
RelativePath="..\..\..\src\jrd\TempSpace.h">
</File>
<File
RelativePath="..\..\..\src\jrd\termtype.h">
</File>

View File

@ -172,9 +172,6 @@
<File
RelativePath="..\..\..\src\jrd\divorce.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\dls.cpp">
</File>
<File
RelativePath="..\..\..\gen\jrd\dpm.cpp">
</File>
@ -355,9 +352,6 @@
<File
RelativePath="..\..\..\src\jrd\sort.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\sort_mem.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\sqz.cpp">
</File>
@ -370,6 +364,9 @@
<File
RelativePath="..\..\..\src\jrd\sym.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\TempSpace.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\thd.cpp">
</File>
@ -500,9 +497,6 @@
<File
RelativePath="..\..\..\src\jrd\divorce.h">
</File>
<File
RelativePath="..\..\..\src\jrd\dls_proto.h">
</File>
<File
RelativePath="..\..\..\src\jrd\dmp_proto.h">
</File>
@ -959,6 +953,9 @@
<File
RelativePath="..\..\..\src\jrd\sym_proto.h">
</File>
<File
RelativePath="..\..\..\src\jrd\TempSpace.h">
</File>
<File
RelativePath="..\..\..\src\jrd\termtype.h">
</File>

42
src/common/classes/File.h Normal file
View File

@ -0,0 +1,42 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef FILE_H
#define FILE_H
typedef UINT64 offset_t;
namespace Firebird {
class File {
public:
virtual size_t read(offset_t, void*, size_t) = 0;
virtual size_t write(offset_t, void*, size_t) = 0;
virtual void unlink() = 0;
virtual offset_t getSize() const = 0;
};
} // namespace
#endif // FILE_H

View File

@ -0,0 +1,338 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if defined(WIN_NT)
#include <fcntl.h>
#include <io.h>
#include <process.h>
#include <share.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <windows.h>
#endif
#include "../jrd/gdsassert.h"
#include "../jrd/os/path_utils.h"
#include "../common/classes/TempFile.h"
// Const definitions
static const char* ENV_VAR = "FIREBIRD_TMP";
static const char* DEFAULT_PATH =
#if defined(UNIX)
"/tmp/";
#elif defined(WIN_NT)
"c:\\temp\\";
#elif defined(VMS)
"SYS$SCRATCH:";
#else
NULL;
#endif
static const char* const NAME_PATTERN = "XXXXXX";
static const char* const NAME_LETTERS = "abcdefghijklmnopqrstuvwxyz0123456789";
static const size_t MAX_TRIES = 256;
//
// TempFile::getTempPath
//
// Returns a pathname to the system temporary directory
//
Firebird::PathName TempFile::getTempPath()
{
const char* env_temp = getenv(ENV_VAR);
Firebird::PathName path = env_temp ? env_temp : "";
if (path.empty())
{
#if defined(WIN_NT)
char temp_dir[MAXPATHLEN];
// this checks "TEMP" and "TMP" environment variables
const int len = GetTempPath(sizeof(temp_dir), temp_dir);
if (len && len < sizeof(temp_dir))
{
path = temp_dir;
}
#else
path = getenv("TMP");
#endif
}
if (path.empty())
{
path = DEFAULT_PATH;
}
fb_assert(path.length());
return path;
}
//
// TempFile::create
//
// Creates a temporary file and returns its name
//
Firebird::PathName TempFile::create(const Firebird::PathName& prefix)
{
Firebird::PathName filename;
try {
TempFile file(prefix, false);
filename = file.getName();
}
catch (const Firebird::Exception&) {
// do nothing
}
return filename;
}
//
// TempFile::init
//
// Creates temporary file with a unique filename
//
void TempFile::init(const Firebird::PathName& directory,
const Firebird::PathName& prefix)
{
// set up temporary directory, if not specified
filename = directory;
if (filename.empty())
{
filename = getTempPath();
}
#if defined(WIN_NT)
_timeb t;
_ftime(&t);
__int64 randomness = t.time;
randomness *= 1000;
randomness += t.millitm;
Firebird::PathName suffix = NAME_PATTERN;
for (int tries = 0; tries < MAX_TRIES; tries++)
{
Firebird::PathName name = filename + prefix;
__int64 temp = randomness;
for (int i = 0; i < suffix.length(); i++)
{
suffix[i] = NAME_LETTERS[temp % (strlen(NAME_LETTERS))];
temp /= strlen(NAME_LETTERS);
}
name += suffix;
DWORD attributes = FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_RANDOM_ACCESS;
if (doUnlink)
{
attributes |= FILE_FLAG_DELETE_ON_CLOSE;
}
handle = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_NEW, attributes, NULL);
if (handle != INVALID_HANDLE_VALUE)
{
filename = name;
break;
}
randomness++;
}
if (handle == INVALID_HANDLE_VALUE)
{
Firebird::system_call_failed::raise("CreateFile");
}
#else
filename += prefix;
filename += NAME_PATTERN;
#ifdef HAVE_MKSTEMP
handle = (IPTR) mkstemp(filename.begin());
#else
if (!mktemp(filename.begin()))
{
Firebird::system_call_failed::raise("mktemp");
}
do {
handle = open(filename.c_str(), O_RDWR | O_EXCL | O_CREAT);
} while (handle == -1 && errno == EINTR);
#endif
if (handle == -1)
{
Firebird::system_call_failed::raise("open");
}
if (doUnlink)
{
::unlink(filename.c_str());
}
#endif
doUnlink = false;
}
//
// TempFile::~TempFile
//
// Destructor
//
TempFile::~TempFile()
{
#if defined(WIN_NT)
if (!CloseHandle(handle))
{
Firebird::system_call_failed::raise("CloseHandle");
}
#else
if (::close(handle) == -1)
{
Firebird::system_call_failed::raise("close");
}
#endif
if (doUnlink)
{
::unlink(filename.c_str());
}
}
//
// TempFile::seek
//
// Performs a positioning operation
//
void TempFile::seek(offset_t offset)
{
fb_assert(offset < MAX_SLONG);
if (position == offset)
return;
#if defined(WIN_NT)
position = SetFilePointer(handle, offset, NULL, FILE_BEGIN);
if (position != offset)
{
Firebird::system_call_failed::raise("SetFilePointer");
}
#else
position = ::lseek(handle, offset, SEEK_SET);
if (position != offset)
{
Firebird::system_call_failed::raise("lseek");
}
#endif
if (position > size)
size = position;
}
//
// TempFile::extend
//
// Increases the file size
//
void TempFile::extend(size_t delta)
{
seek(size + delta);
}
//
// TempFile::read
//
// Reads bytes from file
//
size_t TempFile::read(offset_t offset, void* buffer, size_t length)
{
fb_assert(offset + length <= size);
seek(offset);
#if defined(WIN_NT)
DWORD bytes = 0;
if (!ReadFile(handle, buffer, length, &bytes, NULL) ||
bytes != length)
{
Firebird::system_call_failed::raise("ReadFile");
}
#else
const int bytes = ::read(handle, buffer, length);
if (bytes != length)
{
Firebird::system_call_failed::raise("read");
}
#endif
position += bytes;
return bytes;
}
//
// TempFile::write
//
// Writes bytes to file
//
size_t TempFile::write(offset_t offset, void* buffer, size_t length)
{
fb_assert(offset <= size);
seek(offset);
#if defined(WIN_NT)
DWORD bytes = 0;
if (!WriteFile(handle, buffer, length, &bytes, NULL) ||
bytes != length)
{
Firebird::system_call_failed::raise("WriteFile");
}
#else
const int bytes = ::write(handle, buffer, length);
if (bytes != length)
{
Firebird::system_call_failed::raise("write");
}
#endif
position += bytes;
if (position > size)
size = position;
return bytes;
}
//
// TempFile::unlink
//
// Unlinks the file
//
void TempFile::unlink()
{
#if defined(WIN_NT)
doUnlink = true;
#else
::unlink(filename.c_str());
#endif
}

View File

@ -0,0 +1,86 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef TEMP_FILE_H
#define TEMP_FILE_H
#include "firebird.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/File.h"
class TempFile : public Firebird::File {
public:
TempFile(MemoryPool& pool,
const Firebird::PathName& prefix,
const Firebird::PathName& directory,
bool unlink = true)
: filename(pool), position(0), size(0), doUnlink(unlink)
{
init(directory, prefix);
}
TempFile(const Firebird::PathName& prefix,
bool unlink = true)
: position(0), size(0), doUnlink(unlink)
{
init("", prefix);
}
~TempFile();
size_t read(offset_t, void*, size_t);
size_t write(offset_t, void*, size_t);
void unlink();
offset_t getSize() const
{
return size;
}
void extend(size_t);
const Firebird::PathName& getName() const
{
return filename;
}
static Firebird::PathName getTempPath();
static Firebird::PathName create(const Firebird::PathName&);
private:
void init(const Firebird::PathName&, const Firebird::PathName&);
void seek(offset_t);
#if defined(WIN_NT)
HANDLE handle;
#else
int handle;
#endif
Firebird::PathName filename;
int position;
size_t size;
bool doUnlink;
};
#endif // TEMP_FILE_H

View File

@ -52,13 +52,13 @@ const char* GCPolicyDefault = GCPolicyCooperative;
const ConfigImpl::ConfigEntry ConfigImpl::entries[] =
{
{TYPE_STRING, "RootDirectory", (ConfigValue) 0},
{TYPE_INTEGER, "SortMemBlockSize", (ConfigValue) 1048576}, // bytes
{TYPE_INTEGER, "TempBlockSize", (ConfigValue) 1048576}, // bytes
#ifdef SUPERSERVER
{TYPE_INTEGER, "SortMemUpperLimit", (ConfigValue) 67108864}, // bytes
{TYPE_INTEGER, "TempCacheLimit", (ConfigValue) 67108864}, // bytes
#elif defined(WIN_NT) // win32 CS
{TYPE_INTEGER, "SortMemUpperLimit", (ConfigValue) 8388608}, // bytes
{TYPE_INTEGER, "TempCacheLimit", (ConfigValue) 8388608}, // bytes
#else // non-win32 CS
{TYPE_INTEGER, "SortMemUpperLimit", (ConfigValue) 0}, // bytes
{TYPE_INTEGER, "TempCacheLimit", (ConfigValue) 0}, // bytes
#endif
{TYPE_BOOLEAN, "RemoteFileOpenAbility", (ConfigValue) false},
{TYPE_INTEGER, "GuardianOption", (ConfigValue) 1},
@ -279,14 +279,14 @@ const char* Config::getRootDirectory()
return result ? result : sysConfig.root_dir;
}
int Config::getSortMemBlockSize()
int Config::getTempBlockSize()
{
return (int) sysConfig.values[KEY_SORT_MEM_BLOCK_SIZE];
return (int) sysConfig.values[KEY_TEMP_BLOCK_SIZE];
}
int Config::getSortMemUpperLimit()
int Config::getTempCacheLimit()
{
return (int) sysConfig.values[KEY_SORT_MEM_UPPER_LIMIT];
return (int) sysConfig.values[KEY_TEMP_CACHE_LIMIT];
}
bool Config::getRemoteFileOpenAbility()

View File

@ -67,8 +67,8 @@ class Config
enum ConfigKey
{
KEY_ROOT_DIRECTORY, // 0
KEY_SORT_MEM_BLOCK_SIZE, // 1
KEY_SORT_MEM_UPPER_LIMIT, // 2
KEY_TEMP_BLOCK_SIZE, // 1
KEY_TEMP_CACHE_LIMIT, // 2
KEY_REMOTE_FILE_OPEN_ABILITY, // 3
KEY_GUARDIAN_OPTION, // 4
KEY_CPU_AFFINITY_MASK, // 5
@ -127,14 +127,14 @@ public:
static const char* getRootDirectory();
/*
Block size for the sorting manager
Allocation chunk for the temporary spaces
*/
static int getSortMemBlockSize();
static int getTempBlockSize();
/*
Memory usage limit for the sorting manager
Caching limit for the temporary data
*/
static int getSortMemUpperLimit();
static int getTempCacheLimit();
/*
Whether remote (NFS) files can be opened

View File

@ -24,6 +24,7 @@
#include "../common/config/dir_list.h"
#include "../jrd/os/path_utils.h"
#include "../jrd/gds_proto.h"
#include "../jrd/TempSpace.h"
namespace Firebird {
@ -270,13 +271,11 @@ void TempDirectoryList::initTemp()
const PathName TempDirectoryList::getConfigString() const
{
char tmp_buf[MAXPATHLEN];
const char* value = Config::getTempDirectories();
if (!value) {
// Temporary directory configuration has not been defined.
// Let's make default configuration.
gds__temp_dir(tmp_buf);
value = tmp_buf;
return TempFile::getTempPath();
}
return PathName(value);
}

View File

@ -36,17 +36,13 @@
#include "../dudley/ddl_proto.h"
#include "../dudley/hsh_proto.h"
#include "../dudley/lex_proto.h"
#include "../jrd/gds_proto.h"
#include "../common/classes/TempFile.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef SMALL_FILE_NAMES
const char* SCRATCH = "fb_q";
#else
const char* SCRATCH = "fb_query_";
#endif
static int nextchar(void);
static void retchar(SSHORT);
@ -54,7 +50,7 @@ static int skip_white(void);
/* Input line control */
static FILE *input_file, *trace_file;
static FILE *input_file, *trace_file = NULL;
static TEXT *DDL_char, DDL_buffer[256], trace_file_name[MAXPATHLEN];
enum chr_types {
@ -152,10 +148,10 @@ void LEX_fini(void)
*
**************************************/
if (trace_file != NULL)
if (trace_file != NULL) {
fclose(trace_file);
if (trace_file_name[0])
unlink(trace_file_name);
}
}
@ -202,7 +198,7 @@ void LEX_get_text(UCHAR * buffer, TXT text)
length = text->txt_length;
if (fseek(trace_file, start, 0)) {
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
DDL_err(275, NULL, NULL, NULL, NULL, NULL);
/* msg 275: fseek failed */
}
@ -211,7 +207,7 @@ void LEX_get_text(UCHAR * buffer, TXT text)
while (length--)
*p++ = getc(trace_file);
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
}
@ -228,13 +224,10 @@ void LEX_init( void *file)
* scratch trace file to keep all input.
*
**************************************/
#if !(defined WIN_NT)
trace_file = (FILE*) gds__temp_file(TRUE, SCRATCH, 0);
#else
trace_file = (FILE*) gds__temp_file(TRUE, SCRATCH, trace_file_name);
#endif
if (trace_file == (FILE*) - 1)
const Firebird::PathName filename = TempFile::create(SCRATCH);
strcpy(trace_file_name, filename.c_str());
trace_file = fopen(trace_file_name, "w+b");
if (trace_file == (FILE*) -1)
DDL_err(276, NULL, NULL, NULL, NULL, NULL);
/* msg 276: couldn't open scratch file */
@ -268,7 +261,7 @@ void LEX_put_text (FB_API_HANDLE blob, TXT text)
length = text->txt_length;
if (fseek(trace_file, start, 0)) {
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
DDL_err(275, NULL, NULL, NULL, NULL, NULL);
/* msg 275: fseek failed */
}
@ -287,7 +280,7 @@ void LEX_put_text (FB_API_HANDLE blob, TXT text)
/* msg 277: isc_put_segment failed */
}
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
}

View File

@ -57,9 +57,9 @@
#include "../gpre/gpre_meta.h"
#include "../gpre/msc_proto.h"
#include "../gpre/par_proto.h"
#include "../jrd/gds_proto.h"
#include "../gpre/gpreswi.h"
#include "../common/utils_proto.h"
#include "../common/classes/TempFile.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -75,14 +75,10 @@ extern "C" {
// Globals
GpreGlobals gpreGlob;
#ifdef SMALL_FILE_NAMES
const char* const SCRATCH = "fb_q";
#else
const char* const SCRATCH = "fb_query_";
#endif
const char* const SCRATCH = "fb_query_";
const char* const FOPEN_READ_TYPE = "r";
const char* const FOPEN_WRITE_TYPE = "w";
const char* const FOPEN_READ_TYPE = "r";
const char* const FOPEN_WRITE_TYPE = "w";
static bool all_digits(const char*);
static bool arg_is_string(SLONG, TEXT**, const TEXT*);
@ -1387,16 +1383,11 @@ static SLONG compile_module( SLONG start_position, const TEXT* base_directory)
fseek(input_file, start_position, 0);
input_char = input_buffer;
#if !(defined WIN_NT)
trace_file = (FILE *) gds__temp_file(TRUE, SCRATCH, 0);
#else
// PC-like platforms can't delete a file that is open. Therefore
// we will save the name of the temp file for later deletion.
Firebird::PathName filename = TempFile::create(SCRATCH);
strcpy(trace_file_name, filename.c_str());
trace_file = fopen(trace_file_name, "w+b");
trace_file = (FILE *) gds__temp_file(TRUE, SCRATCH, trace_file_name);
#endif
if (trace_file == (FILE *) - 1) {
if (trace_file == (FILE *) -1) {
trace_file = NULL;
CPR_error("Couldn't open scratch file");
return 0;

View File

@ -61,6 +61,7 @@
#include <errno.h>
#include "../common/utils_proto.h"
#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/TempFile.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -505,21 +506,6 @@ static const ri_actions ri_actions_all[] =
{0, 0, 0}
};
// We statically link ISQL against CLIB in MSVC6 and
// hence we've got problems sharing file handles with FBCLIENT.
// Since temp files are deleted by ISQL, let's create them here as well.
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
static FILE* create_temp_file(const TEXT* string, TEXT* expanded_string)
{
gds__temp_dir(expanded_string);
strcat(expanded_string, string);
strcat(expanded_string, TEMP_PATTERN);
mktemp(expanded_string);
return fopen(expanded_string, "w+b");
}
#define gds__temp_file(flag, string, expanded_string) create_temp_file(string, expanded_string)
#endif
int CLIB_ROUTINE main(int argc,
char* argv[])
@ -2753,12 +2739,12 @@ static processing_state copy_table(TEXT* source,
// If there is an alternate database, extract the domains
const bool domain_flag = otherdb[0];
TEXT ftmp[MAXPATHLEN];
isqlGlob.Out = (FILE*) gds__temp_file(TRUE, SCRATCH, ftmp);
if (isqlGlob.Out == (FILE*) - 1) {
Firebird::PathName ftmp = TempFile::create(SCRATCH);
isqlGlob.Out = fopen(ftmp.c_str(), "w+b");
if (isqlGlob.Out == (FILE*) -1) {
// If we can't open a temp file then bail
ISQL_msg_get(FILE_OPEN_ERR, errbuf, ftmp);
ISQL_msg_get(FILE_OPEN_ERR, errbuf, ftmp.c_str());
STDERROUT(errbuf);
Exit_value = FINI_ERROR;
isqlGlob.Out = holdout;
@ -2817,7 +2803,7 @@ static processing_state copy_table(TEXT* source,
}
}
unlink(ftmp);
unlink(ftmp.c_str());
isqlGlob.Out = holdout;
return (SKIP);
@ -3097,8 +3083,10 @@ static void do_isql()
// File used to edit sessions
Ofp = (FILE*) gds__temp_file(TRUE, SCRATCH, Tmpfile);
if (Ofp == (FILE*) - 1)
const Firebird::PathName filename = TempFile::create(SCRATCH);
strcpy(Tmpfile, filename.c_str());
Ofp = fopen(Tmpfile, "w+b");
if (Ofp == (FILE*) -1)
{
// If we can't open a temp file then bail

405
src/jrd/TempSpace.cpp Normal file
View File

@ -0,0 +1,405 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../common/config/config.h"
#include "../common/config/dir_list.h"
#include "../jrd/gdsassert.h"
#include "../jrd/gds_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/os/path_utils.h"
#include "../jrd/TempSpace.h"
// Const definitions
static const size_t MAX_FILE_SIZE = 1073741824; // 1GB
// Static definitions/initializations
Firebird::Mutex TempSpace::initMutex;
Firebird::TempDirectoryList* TempSpace::tempDirs = NULL;
size_t TempSpace::minBlockSize = 0;
offset_t TempSpace::globalCacheUsage = 0;
//
// Generic space block class
//
TempSpace::Block::Block(Block* tail, size_t length)
: next(NULL), size(length)
{
if (tail)
{
tail->next = this;
}
prev = tail;
}
//
// In-memory block class
//
TempSpace::MemoryBlock::MemoryBlock(MemoryPool& pool, Block* tail, size_t length)
: Block(tail, length)
{
ptr = FB_NEW(pool) char[length];
}
TempSpace::MemoryBlock::~MemoryBlock()
{
delete[] ptr;
}
size_t TempSpace::MemoryBlock::read(size_t offset, void* buffer, size_t length)
{
if (offset + length > size)
{
length = size - offset;
}
memcpy(buffer, (char*) ptr + offset, length);
return length;
}
size_t TempSpace::MemoryBlock::write(size_t offset, void* buffer, size_t length)
{
if (offset + length > size)
{
length = size - offset;
}
memcpy((char*) ptr + offset, buffer, length);
return length;
}
//
// On-disk block class
//
TempSpace::FileBlock::FileBlock(TempFile* f, Block* tail, size_t length)
: Block(tail, length), file(f)
{
fb_assert(file);
seek = file->getSize();
}
TempSpace::FileBlock::~FileBlock()
{
}
size_t TempSpace::FileBlock::read(size_t offset, void* buffer, size_t length)
{
if (offset + length > size)
{
length = size - offset;
}
offset += seek;
return file->read(offset, buffer, length);
}
size_t TempSpace::FileBlock::write(size_t offset, void* buffer, size_t length)
{
if (offset + length > size)
{
length = size - offset;
}
offset += seek;
return file->write(offset, buffer, length);
}
//
// TempSpace::TempSpace
//
// Constructor
//
TempSpace::TempSpace(MemoryPool& p, const Firebird::PathName& prefix)
: pool(p), tempFiles(p),
head(NULL), tail(NULL), filePrefix(p, prefix),
logicalSize(0), physicalSize(0), localCacheUsage(0)
{
if (!tempDirs)
{
Firebird::MutexLockGuard guard(initMutex);
if (!tempDirs)
{
MemoryPool& p = *getDefaultMemoryPool();
tempDirs = FB_NEW(p) Firebird::TempDirectoryList(p);
minBlockSize = Config::getTempBlockSize();
}
}
}
//
// TempSpace::~TempSpace
//
// Destructor
//
TempSpace::~TempSpace()
{
while (head)
{
Block* temp = head->next;
delete head;
head = temp;
}
globalCacheUsage -= localCacheUsage;
while (tempFiles.getCount())
{
delete tempFiles.pop();
}
}
//
// TempSpace::read
//
// Reads bytes from the temporary space
//
size_t TempSpace::read(offset_t offset, void* buffer, size_t length)
{
fb_assert(offset + length <= logicalSize);
if (length)
{
// search for the first needed block
Block* block = findBlock(offset);
char* p = static_cast<char*>(buffer);
size_t l = length;
// read data from the block chain
for (Block* itr = block; itr && l;
itr = itr->next, offset = 0)
{
const size_t n = itr->read(offset, p, l);
p += n;
l -= n;
}
fb_assert(!l);
}
return length;
}
//
// TempSpace::write
//
// Writes bytes to the temporary space
//
size_t TempSpace::write(offset_t offset, void* buffer, size_t length)
{
fb_assert(offset <= logicalSize);
if (offset + length > logicalSize)
{
// not enough space, allocate one more block
extend(offset + length - logicalSize);
}
if (length)
{
// search for the first needed block
Block* block = findBlock(offset);
char* p = static_cast<char*>(buffer);
size_t l = length;
// write data to as many blocks as necessary
for (Block* itr = block; itr && l;
itr = itr->next, offset = 0)
{
const size_t n = itr->write(offset, p, l);
p += n;
l -= n;
}
fb_assert(!l);
}
return length;
}
//
// TempSpace::extend
//
// Increases size of the temporary space
//
void TempSpace::extend(size_t size)
{
logicalSize += size;
if (logicalSize > physicalSize)
{
size = FB_ALIGN(size, minBlockSize);
physicalSize += size;
Block* block = NULL;
if (globalCacheUsage + size <= Config::getTempCacheLimit())
{
try
{
// allocate block in virtual memory
block = FB_NEW(pool) MemoryBlock(pool, tail, size);
localCacheUsage += size;
globalCacheUsage += size;
}
catch (const Firebird::BadAlloc&)
{
// not enough memory
}
}
if (!block)
{
// allocate block in the temp file
TempFile* file = setupFile(size);
block = FB_NEW(pool) FileBlock(file, tail, size);
}
// append new block to the chain
if (!head)
{
head = block;
}
tail = block;
}
}
//
// TempSpace::findBlock
//
// Locates the space block corresponding to the given global offset
//
TempSpace::Block* TempSpace::findBlock(offset_t& offset)
{
fb_assert(offset <= logicalSize);
Block* block = NULL;
if (offset < physicalSize / 2)
{
// walk forward
block = head;
while (block && offset >= block->size)
{
offset -= block->size;
block = block->next;
}
fb_assert(block);
}
else
{
// walk backward
block = tail;
while (block && physicalSize - offset > block->size)
{
offset += block->size;
block = block->prev;
}
fb_assert(block);
offset -= physicalSize - block->size;
}
fb_assert(offset <= block->size);
return block;
}
//
// TempSpace::setupFile
//
// Allocates the required space in some temporary file
//
TempFile* TempSpace::setupFile(size_t size)
{
TempFile* file = NULL;
for (size_t i = 0; i < tempDirs->getCount(); i++)
{
Firebird::PathName directory = (*tempDirs)[i];
PathUtils::concatPath(directory, directory, PathUtils::dir_sep);
for (size_t j = 0; j < tempFiles.getCount(); j++)
{
Firebird::PathName dirname, filename;
PathUtils::splitLastComponent(dirname, filename,
tempFiles[j]->getName());
PathUtils::concatPath(dirname, dirname, PathUtils::dir_sep);
if (!directory.compare(dirname) &&
tempFiles[j]->getSize() + size <= MAX_FILE_SIZE)
{
file = tempFiles[i];
break;
}
}
if (!file)
{
fb_assert(size <= MAX_FILE_SIZE);
file = FB_NEW(pool) TempFile(pool, filePrefix, directory);
tempFiles.add(file);
}
fb_assert(file);
try
{
file->extend(size);
}
catch (const Firebird::system_call_failed&)
{
if (i < tempDirs->getCount() - 1)
{
// no room, let's try another directory
Firebird::string text;
text.printf("Temporary directory %s has no free space, "
"attempting to switch to the next configured one",
directory.c_str());
gds__log(text.c_str());
file = NULL;
}
else
{
// no room in all directories
gds__log("No free space found in temporary directories");
throw;
}
}
if (file)
{
break;
}
}
fb_assert(file);
return file;
}

113
src/jrd/TempSpace.h Normal file
View File

@ -0,0 +1,113 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef TEMP_SPACE_H
#define TEMP_SPACE_H
#include "firebird.h"
#include "../common/classes/fb_string.h"
#include "../common/classes/array.h"
#include "../common/classes/TempFile.h"
#include "../common/config/dir_list.h"
class TempSpace : public Firebird::File {
public:
TempSpace(MemoryPool&, const Firebird::PathName&);
virtual ~TempSpace();
size_t read(offset_t, void*, size_t);
size_t write(offset_t, void*, size_t);
void unlink() {}
offset_t getSize() const
{
return logicalSize;
}
void extend(size_t);
private:
// Generic space block
class Block {
public:
Block(Block*, size_t);
virtual ~Block() {}
virtual size_t read(size_t, void*, size_t) = 0;
virtual size_t write(size_t, void*, size_t) = 0;
Block *prev;
Block *next;
size_t size;
};
class MemoryBlock : public Block {
public:
MemoryBlock(MemoryPool&, Block*, size_t);
~MemoryBlock();
size_t read(size_t, void*, size_t);
size_t write(size_t, void*, size_t);
private:
void* ptr;
};
class FileBlock : public Block {
public:
FileBlock(TempFile*, Block*, size_t);
~FileBlock();
size_t read(size_t, void*, size_t);
size_t write(size_t, void*, size_t);
private:
TempFile* file;
size_t seek;
};
Block* findBlock(offset_t&);
TempFile* setupFile(size_t);
virtual bool adjustCacheSize(long) const
{
return false;
}
MemoryPool& pool;
Firebird::PathName filePrefix;
offset_t logicalSize;
offset_t physicalSize;
offset_t localCacheUsage;
Block* head;
Block* tail;
Firebird::Array<TempFile*> tempFiles;
static Firebird::Mutex initMutex;
static Firebird::TempDirectoryList* tempDirs;
static size_t minBlockSize;
static offset_t globalCacheUsage;
};
#endif // TEMP_SPACE_H

View File

@ -1,199 +0,0 @@
/*
* PROGRAM: JRD Access Method
* MODULE: dls.cpp
* DESCRIPTION: Temporary file management
* The file contains set of functions that
* are used to manage directory list.
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 26-Sept-2001 Paul Beach - External File Directory Config. Parameter
*/
#include "firebird.h"
#include <string.h>
#include <stdlib.h>
#include "../jrd/sort.h"
#include "../jrd/dls_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/gdsassert.h"
#include "../jrd/file_params.h"
#include "../common/config/dir_list.h"
using namespace Jrd;
static mutexed_dir_list DLS_cfg_tmpdir; /* directory list object */
/* Note that the only kind of writing permitted on the function_dir_list is
* appending a new entry to the existing (possibly empty) list.
* Therefore, we only need a write-lock to protect against
* simultaneous updates: readers don't need a lock because they'll
* always see either the old or the new state of the list, never an
* in-between state.
*
* Also note that for this argument to be correct, it is necessary
* that updaters NULL out the "next" pointer of a new element
* *before*, not after, they append the element to the list, so that
* the list is at all times terminated by a NULL pointer.
*/
bool DLS_get_temp_space(ULONG size, sort_work_file* sfb)
{
/**************************************
*
* D L S _ g e t _ t e m p _ s p a c e
*
**************************************
*
* Functional description
* Allocate disk space with required size
*
**************************************/
bool result = false;
fb_assert(size > (ULONG) 0);
fb_assert(sfb);
mutexed_dir_list* ptr = DLS_get_access();
Firebird::MutexLockGuard guard(ptr->mdls_mutex);
if (!sfb->sfb_dls) {
/* allocate temp. space starting search from the begining of the dir_list */
for (sfb->sfb_dls = ptr->mdls_dls;
sfb->sfb_dls;
sfb->sfb_dls = sfb->sfb_dls->dls_next)
{
if (size <= (sfb->sfb_dls->dls_size - sfb->sfb_dls->dls_inuse)) {
sfb->sfb_dls->dls_inuse += size;
result = true;
break;
}
}
}
else {
/* allocate temp. space from the current dir_list entry */
if (size <= (sfb->sfb_dls->dls_size - sfb->sfb_dls->dls_inuse)) {
sfb->sfb_dls->dls_inuse += size;
result = true;
}
}
return result;
}
void DLS_put_temp_space(sort_work_file* sfb)
{
/**************************************
*
* D L S _ p u t _ t e m p _ s p a c e
*
**************************************
*
* Functional description
* Release disk space occupied by sort file
*
**************************************/
if (sfb && sfb->sfb_dls) {
mutexed_dir_list* ptr = DLS_get_access();
Firebird::MutexLockGuard guard(ptr->mdls_mutex);
fb_assert(sfb->sfb_dls->dls_inuse >= sfb->sfb_file_size);
if (sfb->sfb_dls->dls_inuse > sfb->sfb_file_size)
sfb->sfb_dls->dls_inuse -= sfb->sfb_file_size;
else
sfb->sfb_dls->dls_inuse = 0;
}
}
bool DLS_add_dir(ULONG size, const TEXT* dir_name)
{
/**************************************
*
* D L S _ a d d _ d i r
*
**************************************
*
* Functional description
* Add new entry to the temporary directory list.
*
**************************************/
/* allocate dir_list structure */
dir_list* new_dls = (dir_list*) gds__alloc((SLONG) (sizeof(dir_list) +
sizeof(TEXT) * strlen(dir_name)));
if (!new_dls)
return false;
strcpy(new_dls->dls_directory, dir_name);
new_dls->dls_size = size;
new_dls->dls_inuse = 0;
new_dls->dls_next = NULL;
/* get access to directory list object */
mutexed_dir_list* mdls = DLS_get_access();
Firebird::MutexLockGuard guard(mdls->mdls_mutex);
/* add new entry to the end of list */
if (!mdls->mdls_dls) {
mdls->mdls_dls = new_dls;
}
else {
dir_list* dls_iterator = mdls->mdls_dls;
while (dls_iterator->dls_next)
dls_iterator = dls_iterator->dls_next;
dls_iterator->dls_next = new_dls;
}
return true;
}
mutexed_dir_list* DLS_get_access(void)
{
/**************************************
*
* D L S _ g e t _ a c c e s s
*
**************************************
*
* Functional description
* Return pointer to the temporary file configuration
*
**************************************/
static bool is_initialized = false;
if (!is_initialized) {
is_initialized = true;
Firebird::TempDirectoryList dir_list(*getDefaultMemoryPool());
for (int i = 0; i < dir_list.getCount(); i++) {
const Firebird::PathName& path = dir_list[i];
DLS_add_dir(ALLROOM, path.c_str());
}
}
return (&DLS_cfg_tmpdir);
}

View File

@ -1,37 +0,0 @@
/*
* PROGRAM: JRD Access Method
* MODULE: dls_proto.h
* DESCRIPTION: Temporary file management
*
* The contents of this file are subject to the Interbase Public
* License Version 1.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.Inprise.com/IPL.html
*
* Software distributed under the License is distributed on an
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
* or implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
* 26-Sept-2001 Paul Beach - External File Directory Config. Parameter
*/
#ifndef JRD_DLS_PROTO_H
#define JRD_DLS_PROTO_H
#include "../jrd/sort.h"
bool DLS_get_temp_space(ULONG, Jrd::sort_work_file*);
void DLS_put_temp_space(Jrd::sort_work_file*);
bool DLS_add_dir(ULONG, const TEXT*);
mutexed_dir_list* DLS_get_access(void);
#endif // JRD_DLS_PROTO_H

View File

@ -2801,10 +2801,7 @@ static void compute_agg_distinct(thread_db* tdbb, jrd_nod* node)
/* Sort the values already "put" to sort */
if (!SORT_sort(tdbb->tdbb_status_vector, asb_impure->iasb_sort_handle))
{
ERR_punt();
}
SORT_sort(tdbb->tdbb_status_vector, asb_impure->iasb_sort_handle);
/* Now get the sorted/projected values and compute the aggregate */
@ -3523,14 +3520,9 @@ static void init_agg_distinct(thread_db* tdbb, const jrd_nod* node)
impure_agg_sort* asb_impure = (impure_agg_sort*) ((char*) request + asb->nod_impure);
const sort_key_def* sort_key = asb->asb_key_desc;
sort_context* handle =
SORT_init(tdbb->tdbb_status_vector,
ROUNDUP_LONG(sort_key->skd_length), 1, 1, sort_key,
reject_duplicate, 0,
tdbb->tdbb_attachment, 0);
if (!(asb_impure->iasb_sort_handle = handle))
ERR_punt();
asb_impure->iasb_sort_handle =
SORT_init(tdbb, ROUNDUP_LONG(sort_key->skd_length),
1, 1, sort_key, reject_duplicate, 0, 0);
}

View File

@ -2350,133 +2350,6 @@ void API_ROUTINE gds__sqlcode_s(const ISC_STATUS* status_vector, ULONG* sqlcode)
}
void API_ROUTINE gds__temp_dir(TEXT* buffer)
{
/**************************************
*
* g d s _ _ t e m p _ d i r
*
**************************************
*
* Functional description
* Return temporary directory.
*
**************************************/
buffer[0] = 0;
gdsPrefixInit();
strcpy(buffer, fbTempDir); // safe - no BO
}
void* API_ROUTINE gds__temp_file(
BOOLEAN stdio_flag, const TEXT* string,
TEXT* expanded_string, TEXT* dir, BOOLEAN unlink_flag)
{
/**************************************
*
* g d s _ _ t e m p _ f i l e
*
**************************************
*
* Functional description
* Create and open a temp file with a given location.
* Unless the address of a buffer for the expanded file name string is
* given, make up the file "pre-deleted". Return -1 on failure.
* If unlink_flag is TRUE than file is marked as pre-deleted even if
* expanded_string is not NULL.
* NOTE
* Function returns untyped handle that needs to be casted to either FILE
* or used as file descriptor. This is ugly and needs to be fixed probably
* via introducing two functions with different return types.
*
**************************************/
TEXT temp_dir[MAXPATHLEN];
const TEXT* directory = dir;
if (!directory) {
gds__temp_dir(temp_dir);
directory = temp_dir;
}
if (strlen(directory) >= MAXPATHLEN - strlen(string) - strlen(TEMP_PATTERN) - 2)
return (void *)-1;
void* result;
#ifdef WIN_NT
/* These are the characters used in temporary filenames. */
static const char letters[] = "abcdefghijklmnopqrstuvwxyz0123456789";
_timeb t;
_ftime(&t);
__int64 randomness = t.time;
randomness *= 1000;
randomness += t.millitm;
for (int tryCount = 0; tryCount < MAX_TMPFILE_TRIES; tryCount++) {
char file_name[MAXPATHLEN];
strcpy(file_name, directory);
if (file_name[strlen(file_name) - 1] != '\\')
strcat(file_name, "\\");
strcat(file_name, string);
char suffix[] = TEMP_PATTERN;
__int64 temp = randomness;
for (size_t i = 0; i < sizeof(suffix) - 1; i++) {
suffix[i] = letters[temp % (sizeof(letters) - 1)];
temp /= sizeof(letters) - 1;
}
strcat(file_name, suffix);
if (expanded_string)
strcpy(expanded_string, file_name);
result = (void*)_sopen(file_name, _O_CREAT | _O_TRUNC | _O_RDWR |
_O_BINARY | _O_SHORT_LIVED | _O_NOINHERIT | _O_EXCL |
(expanded_string && !unlink_flag ? 0 : _O_TEMPORARY),
_SH_DENYRW, _S_IREAD | _S_IWRITE);
if ((int)result != -1 || (errno != EACCES && errno != EEXIST))
break;
randomness++;
}
if ((int)result == -1) return result;
if (stdio_flag) {
if (!(result = fdopen((int) result, "w+b")))
return (void *)-1;
}
#else
TEXT file_name[MAXPATHLEN];
strcpy(file_name, directory);
if (file_name[strlen(file_name) - 1] != '/')
strcat(file_name, "/");
strcat(file_name, string);
strcat(file_name, TEMP_PATTERN);
#ifdef HAVE_MKSTEMP
result = (void *)(IPTR)mkstemp(file_name);
#else
if (mktemp(file_name) == (char *)0)
return (void *)-1;
do {
result = (void *)open(file_name, O_RDWR | O_EXCL | O_CREAT);
} while (result == (void *)-1 && errno == EINTR);
#endif
if (result == (void *)-1)
return result;
if (stdio_flag)
if (!(result = fdopen((int)(IPTR)result, "w+")))
return (void *)-1;
if (expanded_string)
strcpy(expanded_string, file_name);
if (!expanded_string || unlink_flag)
unlink(file_name);
#endif
return result;
}
void API_ROUTINE gds__unregister_cleanup(FPTR_VOID_PTR routine, void *arg)
{
/**************************************

View File

@ -118,9 +118,6 @@ void API_ROUTINE gds__qtoq(const void*, void*);
void API_ROUTINE gds__register_cleanup(FPTR_VOID_PTR, void*);
SLONG API_ROUTINE gds__sqlcode(const ISC_STATUS*);
void API_ROUTINE gds__sqlcode_s(const ISC_STATUS*, ULONG*);
void API_ROUTINE gds__temp_dir(TEXT*);
void* API_ROUTINE gds__temp_file(BOOLEAN, const TEXT*, TEXT*, TEXT* = NULL,
BOOLEAN = FALSE);
void API_ROUTINE gds__unregister_cleanup(FPTR_VOID_PTR, void*);
BOOLEAN API_ROUTINE gds__validate_lib_path(const TEXT*, const TEXT*, TEXT*,
SLONG);

View File

@ -295,13 +295,11 @@ void IDX_create_index(
void* callback_arg =
(idx->idx_flags & idx_unique) ? &ifl_data : NULL;
sort_context* sort_handle = SORT_init(tdbb->tdbb_status_vector,
key_length + sizeof(index_sort_record),
2, 1, key_desc, callback, callback_arg,
tdbb->tdbb_attachment, 0);
sort_context* sort_handle =
SORT_init(tdbb, key_length + sizeof(index_sort_record),
2, 1, key_desc, callback, callback_arg, 0);
if (!sort_handle)
ERR_punt();
try {
jrd_rel* partner_relation = 0;
USHORT partner_index_id = 0;
@ -335,9 +333,8 @@ void IDX_create_index(
/* Loop thru the relation computing index keys. If there are old versions,
find them, too. */
bool cancel = false;
temporary_key key;
while (!cancel && DPM_next(tdbb, &primary, LCK_read, false, false)) {
while (DPM_next(tdbb, &primary, LCK_read, false, false)) {
if (transaction && !VIO_garbage_collect(tdbb, &primary, transaction))
continue;
if (primary.rpb_flags & rpb_deleted)
@ -475,7 +472,7 @@ void IDX_create_index(
#ifdef SUPERSERVER
if (--tdbb->tdbb_quantum < 0)
cancel = JRD_reschedule(tdbb, 0, false);
JRD_reschedule(tdbb, 0, true);
#endif
}
@ -483,17 +480,20 @@ void IDX_create_index(
if (primary.getWindow(tdbb).win_flags & WIN_large_scan)
--relation->rel_scan_count;
if (cancel || !SORT_sort(tdbb->tdbb_status_vector, sort_handle)) {
SORT_fini(sort_handle, tdbb->tdbb_attachment);
ERR_punt();
}
SORT_sort(tdbb->tdbb_status_vector, sort_handle);
if (ifl_data.ifl_duplicates > 0) {
SORT_fini(sort_handle, tdbb->tdbb_attachment);
ERR_post(isc_no_dup, isc_arg_string,
ERR_cstring(index_name), 0);
}
}
catch (const Firebird::Exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
SORT_fini(sort_handle, tdbb->tdbb_attachment);
ERR_punt();
}
BTR_create(tdbb, relation, idx, key_length, sort_handle, selectivity);
if (ifl_data.ifl_duplicates > 0) {

View File

@ -85,7 +85,6 @@
#include "../jrd/cch_proto.h"
#include "../jrd/cmp_proto.h"
#include "../jrd/dbg_proto.h"
#include "../jrd/dls_proto.h"
#include "../jrd/dyn_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/exe_proto.h"
@ -123,6 +122,7 @@
#include "../jrd/flags.h"
#include "../common/config/config.h"
#include "../common/config/dir_list.h"
#include "../jrd/plugin_manager.h"
#include "../jrd/db_alias.h"
#include "../jrd/IntlManager.h"
@ -762,7 +762,7 @@ ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status,
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
pageSpace->file =
PIO_open(dbb, expanded_name, options.dpb_trace != 0, NULL, file_name);
PIO_open(dbb, expanded_name, options.dpb_trace != 0, file_name);
SHUT_init(dbb);
PAG_header(file_name.c_str(), file_name.length(), false);
INI_init2();
@ -6075,24 +6075,10 @@ TEXT* JRD_num_attachments(TEXT* const buf, USHORT buf_len, USHORT flag,
/* Get drive letters for temp directories */
if (flag == JRD_info_drivemask) {
mutexed_dir_list* ptr = DLS_get_access();
for (dir_list* dirs = ptr->mdls_dls; dirs; dirs = dirs->dls_next) {
ExtractDriveLetter(dirs->dls_directory, &drive_mask);
}
}
/* Get drive letters for sort files */
if (flag == JRD_info_drivemask)
{
for (const sort_context* scb = attach->att_active_sorts; scb;
scb = scb->scb_next)
{
for (const sort_work_file* sfb = scb->scb_sfb; sfb;
sfb = sfb->sfb_next)
{
ExtractDriveLetter(sfb->sfb_file_name, &drive_mask);
}
const Firebird::TempDirectoryList dirList;
for (size_t i = 0; i < dirList.getCount(); i++) {
const Firebird::PathName& path = dirList[i];
ExtractDriveLetter(path.c_str(), &drive_mask);
}
}
#endif

View File

@ -1206,7 +1206,7 @@ bool BackupManager::actualize_state(thread_db* tdbb) throw()
#endif
try {
NBAK_TRACE(("Open difference file"));
diff_file = PIO_open(database, diff_name, false, NULL, diff_name);
diff_file = PIO_open(database, diff_name, false, diff_name);
}
catch (const Firebird::Exception& ex) {
#ifdef SUPERSERVER

View File

@ -37,7 +37,6 @@ struct blk;
int PIO_add_file(Jrd::Database*, Jrd::jrd_file*, const Firebird::PathName&, SLONG);
void PIO_close(Jrd::jrd_file*);
Jrd::jrd_file* PIO_create(Jrd::Database*, const Firebird::PathName&, bool, bool);
int PIO_connection(const Firebird::PathName&);
int PIO_expand(const TEXT*, USHORT, TEXT*, size_t);
void PIO_flush(Jrd::jrd_file*);
void PIO_force_write(Jrd::jrd_file*, bool);
@ -45,7 +44,7 @@ void PIO_header(Jrd::Database*, SCHAR*, int);
SLONG PIO_max_alloc(Jrd::Database*);
SLONG PIO_act_alloc(Jrd::Database*);
Jrd::jrd_file* PIO_open(Jrd::Database*, const Firebird::PathName&, bool,
blk*, const Firebird::PathName&);
const Firebird::PathName&);
bool PIO_read(Jrd::jrd_file*, Jrd::BufferDesc*, Ods::pag*, ISC_STATUS*);
#ifdef SUPERSERVER_V2

View File

@ -205,27 +205,6 @@ void PIO_close(jrd_file* main_file)
}
int PIO_connection(const Firebird::PathName& file_name)
{
/**************************************
*
* P I O _ c o n n e c t i o n
*
**************************************
*
* Functional description
* Analyze a file specification and determine whether a page/lock
* server is required and available. If so, return a "connection"
* block. If not, return NULL.
*
* Note: The file name must have been expanded prior to this call.
*
**************************************/
return 0;
}
jrd_file* PIO_create(Database* dbb, const Firebird::PathName& string, bool overwrite, bool /*temporary*/)
{
/**************************************
@ -562,7 +541,6 @@ SLONG PIO_act_alloc(Database* dbb)
jrd_file* PIO_open(Database* dbb,
const Firebird::PathName& string,
bool trace_flag,
blk* connection,
const Firebird::PathName& file_name)
{
/**************************************
@ -572,8 +550,7 @@ jrd_file* PIO_open(Database* dbb,
**************************************
*
* Functional description
* Open a database file. If a "connection" block is provided, use
* the connection to communication with a page/lock server.
* Open a database file.
*
**************************************/
int desc, flag;

View File

@ -62,7 +62,6 @@ entry(gds__attach_database)
entry(perf_format)
entry(perf_get_info)
entry(perf_report)
entry(gds__temp_file)
entry(gds__vax_integer)
entry(gds__encode)
entry(gds__decode)

View File

@ -161,28 +161,6 @@ void PIO_close(jrd_file* main_file)
}
int PIO_connection(const Firebird::PathName& file_name)
{
/**************************************
*
* P I O _ c o n n e c t i o n
*
**************************************
*
* Functional description
* Analyze a file specification and determine whether a page/lock
* server is required and available. If so, return a "connection"
* block. If not, return NULL.
*
* Note: The file name must have been expanded prior to this call.
*
**************************************/
return 0;
}
jrd_file* PIO_create(Database* dbb, const Firebird::PathName& string, bool overwrite, bool temporary)
{
/**************************************
@ -482,7 +460,6 @@ SLONG PIO_act_alloc(Database* dbb)
jrd_file* PIO_open(Database* dbb,
const Firebird::PathName& string,
bool trace_flag,
blk* connection,
const Firebird::PathName& file_name)
{
/**************************************
@ -492,9 +469,7 @@ jrd_file* PIO_open(Database* dbb,
**************************************
*
* Functional description
* Open a database file. If a "connection"
* block is provided, use the connection
* to communicate with a page/lock server.
* Open a database file.
*
**************************************/
const TEXT* ptr = (string.hasData() ? string : file_name).c_str();

View File

@ -76,7 +76,6 @@
#include "../jrd/os/path_utils.h"
#include "../jrd/ibase.h"
#include "../jrd/gdsassert.h"
//#include "../jrd/license.h"
#include "../jrd/lck.h"
#include "../jrd/sdw.h"
#include "../jrd/cch.h"
@ -86,7 +85,6 @@
#include "../jrd/all.h"
#endif
#include "../jrd/cch_proto.h"
#include "../jrd/dls_proto.h"
#include "../jrd/dpm_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/gds_proto.h"
@ -98,6 +96,7 @@
#include "../jrd/os/pio_proto.h"
#include "../jrd/thd.h"
#include "../jrd/isc_f_proto.h"
#include "../jrd/TempSpace.h"
using namespace Jrd;
using namespace Ods;
@ -299,6 +298,7 @@ const SSHORT CLASS = CLASS_DARWIN_PPC;
const SSHORT CLASS = CLASS_LINUX_AMD64;
#endif
static const char* const SCRATCH = "fb_table_";
// CVC: Since nobody checks the result from this function (strange!), I changed
// bool to void as the return type but left the result returned as comment.
@ -493,7 +493,10 @@ USHORT PAG_add_file(const TEXT* file_name, SLONG start)
#ifdef SUPPORT_RAW_DEVICES
/* The following lines (taken from PAG_format_header) are needed to identify
this file in raw_devices_validate_database as a valid database attachment. */
MOV_time_stamp(reinterpret_cast<ISC_TIMESTAMP*>(header->hdr_creation_date));
*(ISC_TIMESTAMP*)header->hdr_creation_date = Firebird::TimeStamp().value();
// should we include milliseconds or not?
//Firebird::TimeStamp::round_time(header->hdr_creation_date->timestamp_time, 0);
header->hdr_ods_version = ODS_VERSION | ODS_FIREBIRD_FLAG;
header->hdr_implementation = CLASS;
header->hdr_ods_minor = ODS_CURRENT;
@ -632,38 +635,8 @@ void PAG_attach_temp_pages(thread_db* tdbb, USHORT pageSpaceID)
PageSpace* pageSpaceTemp = dbb->dbb_page_manager.addPageSpace(pageSpaceID);
if (!pageSpaceTemp->file)
{
mutexed_dir_list* dirs = DLS_get_access();
fb_assert(dirs);
fb_assert(dirs->mdls_dls);
dir_list* dir = dirs->mdls_dls;
ULONG max_size = 0;
for (dir_list* d = dir; d; d = d->dls_next)
{
const ULONG dir_size = d->dls_size - d->dls_inuse;
if (max_size < dir_size)
{
max_size = dir_size;
dir = d;
}
}
long hash = 0;
TEXT* p = dbb->dbb_filename.begin(), *const e = dbb->dbb_filename.end();
for (int i = 0; p < e; p++)
{
hash += *p << i;
i = (i + 8) % 32;
}
Firebird::PathName file_name(dir->dls_directory);
if (file_name.at(file_name.length() - 1) != PathUtils::dir_sep) {
file_name += PathUtils::dir_sep;
}
file_name.printf("%sfb_tmp_%x_%x", file_name.c_str(), (unsigned int)pageSpaceID, hash);
pageSpaceTemp->file = PIO_create(dbb, file_name, false, true);
Firebird::PathName file_name = TempFile::create(SCRATCH);
pageSpaceTemp->file = PIO_create(dbb, file_name, true, true);
PAG_format_pip(tdbb, *pageSpaceTemp);
}
}
@ -972,7 +945,9 @@ void PAG_format_header(void)
WIN window(HEADER_PAGE_NUMBER);
header_page* header = (header_page*) CCH_fake(tdbb, &window, 1);
header->hdr_header.pag_scn = 0;
MOV_time_stamp(reinterpret_cast<ISC_TIMESTAMP*>(header->hdr_creation_date));
*(ISC_TIMESTAMP*)header->hdr_creation_date = Firebird::TimeStamp().value();
// should we include milliseconds or not?
//Firebird::TimeStamp::round_time(header->hdr_creation_date->timestamp_time, 0);
header->hdr_header.pag_type = pag_header;
header->hdr_page_size = dbb->dbb_page_size;
header->hdr_ods_version = ODS_VERSION | ODS_FIREBIRD_FLAG;
@ -1523,11 +1498,7 @@ void PAG_init2(USHORT shadow_number)
isc_arg_end);
}
file->fil_next = PIO_open(dbb,
file_name,
false,
0,
file_name);
file->fil_next = PIO_open(dbb, file_name, false, file_name);
file->fil_max_page = last_page;
file = file->fil_next;
if (dbb->dbb_flags & DBB_force_write)

View File

@ -50,7 +50,6 @@
#include "../jrd/lck.h"
#include "../jrd/cch.h"
#include "../jrd/tra.h"
#include "../jrd/sort_mem.h"
#include "gen/iberror.h"
#include "../jrd/gdsassert.h"
#include "../jrd/dpm_proto.h"
@ -560,12 +559,7 @@ static void close_merge(thread_db* tdbb, RecordSource* rsb, irsb_mrg* impure)
merge_file* mfb = &tail->irsb_mrg_file;
sort_work_file* sfb = mfb->mfb_sfb;
if (sfb) {
if (sfb->sfb_file_name) {
close(sfb->sfb_file);
unlink(sfb->sfb_file_name);
delete[] sfb->sfb_file_name;
}
delete sfb->sfb_mem;
delete sfb->sfb_space;
delete sfb;
mfb->mfb_sfb = 0;
}
@ -1949,11 +1943,6 @@ static bool get_record(thread_db* tdbb,
{
select_node = NULL;
}
EVL_expr(tdbb, column_node->nod_arg[0]);
if (request->req_flags & req_null) {
return false;
}
}
if (column_node && (request->req_flags & req_ansi_any))
{
@ -2413,11 +2402,9 @@ static UCHAR *get_sort(thread_db* tdbb, RecordSource* rsb
ULONG* data = 0;
#ifdef SCROLLABLE_CURSORS
SORT_get(tdbb->tdbb_status_vector, impure->irsb_sort_handle,
&data, mode);
SORT_get(tdbb->tdbb_status_vector, impure->irsb_sort_handle, &data, mode);
#else
SORT_get(tdbb->tdbb_status_vector, impure->irsb_sort_handle,
&data);
SORT_get(tdbb->tdbb_status_vector, impure->irsb_sort_handle, &data);
#endif
return reinterpret_cast<UCHAR*>(data);
@ -2736,20 +2723,17 @@ static void open_sort(thread_db* tdbb, RecordSource* rsb, irsb_sort* impure, UIN
// Initialize for sort. If this is really a project operation,
// establish a callback routine to reject duplicate records.
sort_context* handle = SORT_init(tdbb->tdbb_status_vector,
map->smb_length,
map->smb_keys,
map->smb_keys,
map->smb_key_desc,
((map->smb_flags & SMB_project) ? reject : NULL), 0,
tdbb->tdbb_attachment, max_records);
if (!(impure->irsb_sort_handle = handle))
ERR_punt();
impure->irsb_sort_handle =
SORT_init(tdbb, map->smb_length, map->smb_keys,
map->smb_keys, map->smb_key_desc,
((map->smb_flags & SMB_project) ? reject : NULL),
0, max_records);
// Mark sort_context with the impure area pointer
handle->scb_impure = impure;
impure->irsb_sort_handle->scb_impure = impure;
try {
// Pump the input stream dry while pushing records into sort. For
// each record, map all fields into the sort record. The reverse
@ -2765,7 +2749,7 @@ static void open_sort(thread_db* tdbb, RecordSource* rsb, irsb_sort* impure, UIN
UCHAR* data = 0;
SORT_put(tdbb->tdbb_status_vector, impure->irsb_sort_handle,
(ULONG **) &data);
(ULONG **) &data);
// Zero out the sort key. This solve a multitude of problems.
@ -2822,8 +2806,15 @@ static void open_sort(thread_db* tdbb, RecordSource* rsb, irsb_sort* impure, UIN
}
}
if (!SORT_sort(tdbb->tdbb_status_vector, impure->irsb_sort_handle))
SORT_sort(tdbb->tdbb_status_vector, impure->irsb_sort_handle);
}
catch (const Firebird::Exception& ex) {
Firebird::stuff_exception(tdbb->tdbb_status_vector, ex);
SORT_fini(impure->irsb_sort_handle, tdbb->tdbb_attachment);
impure->irsb_sort_handle = NULL;
ERR_punt();
}
// For the sake of prudence, set all record parameter blocks to contain
// the most recent format. This is will guarentee that all fields mapped
@ -3184,12 +3175,12 @@ static ULONG read_merge_block(thread_db* tdbb, merge_file* mfb, ULONG block)
*
**************************************/
fb_assert(mfb->mfb_sfb && mfb->mfb_sfb->sfb_file_name);
fb_assert(mfb->mfb_sfb);
mfb->mfb_sfb->sfb_mem->read(tdbb->tdbb_status_vector,
mfb->mfb_block_size * block,
reinterpret_cast<char*>(mfb->mfb_block_data),
mfb->mfb_block_size);
SORT_read_block(tdbb->tdbb_status_vector, mfb->mfb_sfb,
mfb->mfb_block_size * block,
(UCHAR*) mfb->mfb_block_data,
mfb->mfb_block_size);
return block;
}
@ -3389,26 +3380,14 @@ static void write_merge_block(thread_db* tdbb, merge_file* mfb, ULONG block)
**************************************/
sort_work_file* sfb = mfb->mfb_sfb;
if (!sfb) {
sfb = mfb->mfb_sfb = FB_NEW(*getDefaultMemoryPool()) sort_work_file;
MemoryPool& pool = *getDefaultMemoryPool();
sfb = mfb->mfb_sfb = FB_NEW(pool) sort_work_file;
memset(sfb, 0, sizeof(sort_work_file));
}
if (!sfb->sfb_file_name) {
TEXT file_name[MAXPATHLEN];
// Cast is ok because stdio_flag is false
sfb->sfb_file = (int) (IPTR) gds__temp_file(FALSE, SCRATCH, file_name);
if (sfb->sfb_file == -1)
SORT_error(tdbb->tdbb_status_vector, sfb, "open", isc_io_error,
errno);
sfb->sfb_file_name =
FB_NEW(*getDefaultMemoryPool()) char[strlen(file_name) + 1];
strcpy(sfb->sfb_file_name, file_name);
sfb->sfb_mem = FB_NEW (*getDefaultMemoryPool()) SortMem(sfb, mfb->mfb_block_size);
sfb->sfb_space = FB_NEW(pool) TempSpace(pool, SCRATCH);
}
sfb->sfb_mem->write(tdbb->tdbb_status_vector,
mfb->mfb_block_size * block,
reinterpret_cast<char*>(mfb->mfb_block_data),
mfb->mfb_block_size);
SORT_write_block(tdbb->tdbb_status_vector, sfb,
mfb->mfb_block_size * block,
(UCHAR*) mfb->mfb_block_data,
mfb->mfb_block_size);
}

View File

@ -974,7 +974,7 @@ void SDW_start(const TEXT* file_name,
try {
shadow_file =
PIO_open(dbb, expanded_name, false, 0, file_name);
PIO_open(dbb, expanded_name, false, file_name);
if (dbb->dbb_flags & DBB_force_write) {
PIO_force_write(shadow_file, true);
@ -1234,7 +1234,7 @@ static bool check_for_file(const SCHAR* name, USHORT length)
// This use of PIO_open is NOT checked against DatabaseAccess configuration
// parameter. It's not required, because here we only check for presence of
// existing file, never really use (or create) it.
jrd_file* temp_file = PIO_open(dbb, path, false, 0, path);
jrd_file* temp_file = PIO_open(dbb, path, false, path);
PIO_close(temp_file);
} // try
catch (const Firebird::Exception& ex) {

File diff suppressed because it is too large Load Diff

View File

@ -29,12 +29,12 @@
#include "../jrd/jrd_blks.h"
#include "../include/fb_blk.h"
#include "../jrd/TempSpace.h"
namespace Jrd {
// Forward declaration
struct sort_work_file;
class SortMem;
class Attachment;
struct irsb_sort;
struct merge_control;
@ -203,7 +203,6 @@ struct run_control
ULONG run_max_records; /* total number of records in run */
#endif
USHORT run_depth; /* Number of "elementary" runs */
sort_work_file* run_sfb; /* Run sort file block */
ULONG run_seek; /* Offset in file of run */
ULONG run_size; /* Length of run in work file */
#ifdef SCROLLABLE_CURSORS
@ -212,7 +211,7 @@ struct run_control
sort_record* run_record; /* Next record in run */
SORTP* run_buffer; /* Run buffer */
SORTP* run_end_buffer; /* End of buffer */
ULONG run_buff_alloc; /* ALlocated buffer flag */
bool run_buff_alloc; /* ALlocated buffer flag */
};
/* Merge control block */
@ -231,22 +230,17 @@ struct merge_control
struct work_file_space
{
work_file_space* wfs_next;
ULONG wfs_position; /* Starting position of free space */
ULONG wfs_size; /* Length of free space */
size_t wfs_position; /* Starting position of free space */
size_t wfs_size; /* Length of free space */
};
/* Sort work file control block */
struct sort_work_file
{
sort_work_file* sfb_next;
int sfb_file; /* File descriptor */
TEXT* sfb_file_name; /* ALLOC: File name for deletion */
ULONG sfb_file_size; /* Real size of the work file */
work_file_space* sfb_file_space; /* ALLOC: Available space in work file */
work_file_space* sfb_free_wfs; /* ALLOC: Free space in work file */
dir_list* sfb_dls; /* Place where file is created */
SortMem* sfb_mem;
TempSpace* sfb_space;
};
/* Sort Context Block */
@ -257,6 +251,7 @@ typedef bool (*FPTR_REJECT_DUP_CALLBACK)(const UCHAR*, const UCHAR*, void*);
struct sort_context
{
MemoryPool* scb_pool;
sort_context* scb_next; /* Next known sort in system */
SORTP *scb_memory; /* ALLOC: Memory for sort */
SORTP *scb_end_memory; /* End of memory */
@ -273,7 +268,7 @@ struct sort_context
ULONG scb_key_length; /* Key length */
ULONG scb_unique_length; /* Unique key length, used when duplicates eliminated */
ULONG scb_records; /* Number of records */
//UINT64 scb_max_records; // Maximum number of records to store . Unused.
//UINT64 scb_max_records; // Maximum number of records to store. Unused.
sort_work_file* scb_sfb; /* ALLOC: List of scratch files, if open */
run_control* scb_runs; /* ALLOC: Run on scratch file, if any */
merge_control* scb_merge; /* Top level merge block */

View File

@ -1,347 +0,0 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2002 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "../common/config/config.h"
#include "../jrd/gds_proto.h"
#include "../jrd/sort.h"
#include "../jrd/sort_proto.h"
#include "../jrd/gdsassert.h"
#include "../jrd/sort_mem.h"
using namespace Jrd;
bool SortMem::is_initialized = false;
size_t SortMem::mem_block_size;
size_t SortMem::mem_upper_limit;
size_t SortMem::mem_total_size = 0;
/******************************************************************************
*
* Generic storage block implementation
*/
SortMem::Block::Block(Block *tail, size_t length)
: next(0), size(length)
{
// Link block with the chain
if (tail)
{
tail->next = this;
}
prev = tail;
}
/******************************************************************************
*
* Virtual memory block implementation
*/
SortMem::MemoryBlock::MemoryBlock(Block* tail, size_t length)
: Block(tail, length)
{
// Allocate virtual memory block
address = FB_NEW(*getDefaultMemoryPool()) char[size];
}
SortMem::MemoryBlock::~MemoryBlock()
{
// Free virtual memory block
delete[] address;
}
size_t SortMem::MemoryBlock::read(ISC_STATUS *status, size_t position, char *buffer, size_t length)
{
// Read block from memory
if (position + length > size)
{
length = size - position;
}
memcpy(buffer, address + position, length);
return length;
}
size_t SortMem::MemoryBlock::write(ISC_STATUS *status, size_t position, char *buffer, size_t length)
{
// Write block to memory
if (position + length > size)
{
length = size - position;
}
memcpy(address + position, buffer, length);
return length;
}
/******************************************************************************
*
* File block implementation
*/
SortMem::FileBlock::FileBlock(Block *tail, size_t length, sort_work_file* blk,
size_t position)
: Block(tail, length), file(blk), offset(position)
{
}
SortMem::FileBlock::~FileBlock()
{
}
size_t SortMem::FileBlock::read(ISC_STATUS *status, size_t position, char *buffer, size_t length)
{
// Read block from file
if (position + length > size)
{
length = size - position;
}
return SORT_read_block(status, file, offset + position,
reinterpret_cast<unsigned char*>(buffer), length) - offset - position;
// _lseek(file->sfb_file, offset + position, SEEK_SET);
// return _read(file->sfb_file, buffer, length);
}
size_t SortMem::FileBlock::write(ISC_STATUS *status, size_t position, char *buffer, size_t length)
{
// Write block to file
if (position + length > size)
{
length = size - position;
}
return SORT_write_block(status, file, offset + position,
reinterpret_cast<unsigned char*>(buffer), length) - offset - position;
// _lseek(file->sfb_file, offset + position, SEEK_SET);
// return _write(file->sfb_file, buffer, length);
}
/******************************************************************************
*
* Virtual scratch file implementation
*/
SortMem::SortMem(sort_work_file* blk, size_t size)
: internal(blk), logical_size(0), physical_size(0), file_size(0), head(0), tail(0)
{
// Initialize itself
if (!is_initialized)
{
mem_block_size = Config::getSortMemBlockSize();
mem_upper_limit = Config::getSortMemUpperLimit();
is_initialized = true;
}
// Allocate one block
allocate(size);
}
SortMem::~SortMem()
{
// Free all allocated blocks
while (tail)
{
Block *block = tail->prev;
delete tail;
tail = block;
}
// We've just freed some memory
mem_total_size -= physical_size - file_size;
}
void SortMem::allocate(size_t size)
{
if (size > 0)
{
logical_size += size;
bool mem_allocated = false;
// We've already got enough space to write data of the given size
if (logical_size > physical_size)
{
Block *block;
// Calculate how much virtual memory we should allocate
size_t smart_size = (mem_block_size > size) ? mem_block_size : size;
// Check whether virtual memory should be allocated or file should be used instead
if (mem_total_size + smart_size <= mem_upper_limit)
{
// Allocate block in virtual memory
try
{
block = FB_NEW (*getDefaultMemoryPool())
MemoryBlock(tail, smart_size);
mem_allocated = true;
}
// Not enough memory to allocate block
catch (Firebird::BadAlloc)
{
// Check whether we can try to allocate less memory
if (smart_size > size)
{
// Allocate minimal possible amount of memory once more
smart_size = size;
try
{
block = FB_NEW (*getDefaultMemoryPool())
MemoryBlock(tail, smart_size);
mem_allocated = true;
}
catch (Firebird::BadAlloc) {}
}
}
if (mem_allocated)
{
physical_size += smart_size;
// We've just allocated some virtual memory
mem_total_size += smart_size;
}
}
if (!mem_allocated)
{
// Allocate block on disk
block = FB_NEW (*getDefaultMemoryPool())
FileBlock(tail, size, internal, file_size);
physical_size += size;
// We've just allocated some file storage
file_size += size;
}
// Append new block to the chain
if (!head)
{
head = block;
}
tail = block;
}
}
}
SortMem::Block* SortMem::seek(size_t &position)
{
Block *block = 0;
// Check whether the given offset is valid
if (position < physical_size)
{
if (position < physical_size / 2)
{
// Let's walk forward
block = head;
while (block && position >= block->size)
{
position -= block->size;
block = block->next;
}
}
else
{
// Let's walk backward
block = tail;
while (block && physical_size - position > block->size)
{
position += block->size;
block = block->prev;
}
position += block->size - physical_size;
}
}
return block;
}
size_t SortMem::read(ISC_STATUS *status, size_t position, char *address, size_t length)
{
// If we'are not allowed to use memory, don't waste time
// playing with all these memory blocks - just use scratch file and return
if (!mem_upper_limit)
{
return SORT_read_block(status, internal, position,
reinterpret_cast<unsigned char*>(address), length);
}
size_t copied = 0;
if (length > 0)
{
// Search for the first needed block
size_t pos = position;
Block *block = seek(pos);
fb_assert(block);
// Read data from as many blocks as necessary
for (Block *itr = block; itr && length > 0; itr = itr->next, pos = 0)
{
size_t n = itr->read(status, pos, address, length);
address += n;
copied += n;
length -= n;
}
fb_assert(!length);
}
// New seek value
return position + copied;
}
size_t SortMem::write(ISC_STATUS *status, size_t position, char *address, size_t length)
{
// If we'are not allowed to use memory, don't waste time
// playing with all these memory blocks - just use scratch file and return
if (!mem_upper_limit)
{
return SORT_write_block(status, internal, position,
reinterpret_cast<unsigned char*>(address), length);
}
// There's probably not enough space, try to allocate one more block
if (position + length >= logical_size)
{
allocate(position + length - logical_size);
}
size_t copied = 0;
if (length > 0)
{
// Search for the first needed block
size_t pos = position;
Block *block = seek(pos);
fb_assert(block);
// Write data to as many blocks as necessary
for (Block *itr = block; itr && length > 0; itr = itr->next, pos = 0)
{
size_t n = itr->write(status, pos, address, length);
address += n;
copied += n;
length -= n;
}
fb_assert(!length);
}
// New seek value
return position + copied;
}

View File

@ -1,129 +0,0 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Dmitry Yemanov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2002 Dmitry Yemanov <dimitr@users.sf.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef JRD_SORT_MEM_H
#define JRD_SORT_MEM_H
#include "../jrd/sort.h"
/*
* Virtual scratch file
*/
namespace Jrd {
class SortMem {
private:
// Generic storage block
class Block {
friend class SortMem;
protected:
Block *prev;
Block *next;
size_t size;
public:
// Read bytes from the block into the given buffer
virtual size_t read(ISC_STATUS*, size_t, char*, size_t) = 0;
// Write bytes from the given buffer into the block
virtual size_t write(ISC_STATUS*, size_t, char*, size_t) = 0;
Block(Block*, size_t);
virtual ~Block() {}
};
// Virtual memory block
class MemoryBlock : public Block {
private:
// Base address of the allocated virtual memory
char* address;
public:
size_t read(ISC_STATUS*, size_t, char*, size_t);
size_t write(ISC_STATUS*, size_t, char*, size_t);
MemoryBlock(Block*, size_t);
~MemoryBlock();
};
// File block
class FileBlock : public Block {
private:
// Sort file block
sort_work_file* file;
// File offset
size_t offset;
public:
size_t read(ISC_STATUS*, size_t, char*, size_t);
size_t write(ISC_STATUS*, size_t, char*, size_t);
FileBlock(Block*, size_t, sort_work_file*, size_t);
~FileBlock();
};
// Initialization flag
static bool is_initialized;
// Virtual memory allocation values
static size_t mem_block_size;
static size_t mem_upper_limit;
// Total amount of allocated virtual memory
static size_t mem_total_size;
sort_work_file* internal;
// Virtual scratch file size
size_t logical_size;
// Amount of storage space allocated for this scratch file
size_t physical_size;
// File size on disk
size_t file_size;
// First block in chain
Block *head;
// Last block in chain
Block *tail;
// Allocate one more block, if necessary
void allocate(size_t);
// Convert logical position to the physical one - pair [block, offset]
Block* seek(size_t&);
public:
// Read bytes from the scratch file
size_t read(ISC_STATUS*, size_t, char*, size_t);
// Write bytes into the scratch file
size_t write(ISC_STATUS*, size_t, char*, size_t);
SortMem(sort_work_file*, size_t);
~SortMem();
};
} //namespace Jrd
#endif // JRD_SORT_MEM_H

View File

@ -32,24 +32,20 @@ namespace Jrd {
}
#ifdef SCROLLABLE_CURSORS
void SORT_diddle_key(UCHAR *, Jrd::sort_context*, bool);
void SORT_get(ISC_STATUS*, Jrd::sort_context*, ULONG **, RSE_GET_MODE);
void SORT_read_block(ISC_STATUS*, Jrd::sort_work_file*, ULONG, BLOB_PTR *, ULONG);
void SORT_diddle_key(UCHAR *, Jrd::sort_context*, bool);
void SORT_get(ISC_STATUS*, Jrd::sort_context*, ULONG **, RSE_GET_MODE);
void SORT_read_block(ISC_STATUS*, Jrd::sort_work_file*, ULONG, BLOB_PTR *, ULONG);
#else
void SORT_get(ISC_STATUS*, Jrd::sort_context*, ULONG **);
ULONG SORT_read_block(ISC_STATUS*, Jrd::sort_work_file*, ULONG, BLOB_PTR *,
ULONG);
void SORT_get(ISC_STATUS*, Jrd::sort_context*, ULONG **);
ULONG SORT_read_block(ISC_STATUS*, Jrd::sort_work_file*, ULONG, BLOB_PTR *, ULONG);
#endif
void SORT_error(ISC_STATUS*, Jrd::sort_work_file*, TEXT *, ISC_STATUS, int);
void SORT_fini(Jrd::sort_context*, Jrd::Attachment*);
Jrd::sort_context* SORT_init(ISC_STATUS*, USHORT, USHORT, USHORT, const Jrd::sort_key_def*,
Jrd::FPTR_REJECT_DUP_CALLBACK, void*, Jrd::Attachment*, UINT64);
void SORT_put(ISC_STATUS*, Jrd::sort_context*, ULONG **);
void SORT_shutdown(Jrd::Attachment*);
bool SORT_sort(ISC_STATUS*, Jrd::sort_context*);
ULONG SORT_write_block(ISC_STATUS*, Jrd::sort_work_file*, ULONG, BLOB_PTR *,
ULONG);
void SORT_fini(Jrd::sort_context*, Jrd::Attachment*);
Jrd::sort_context* SORT_init(Jrd::thread_db*, USHORT, USHORT, USHORT, const Jrd::sort_key_def*,
Jrd::FPTR_REJECT_DUP_CALLBACK, void*, UINT64);
void SORT_put(ISC_STATUS*, Jrd::sort_context*, ULONG **);
void SORT_shutdown(Jrd::Attachment*);
void SORT_sort(ISC_STATUS*, Jrd::sort_context*);
ULONG SORT_write_block(ISC_STATUS*, Jrd::sort_work_file*, ULONG, BLOB_PTR *, ULONG);
#endif // JRD_SORT_PROTO_H

View File

@ -37,10 +37,10 @@
#include "../qli/hsh_proto.h"
#include "../qli/lex_proto.h"
#include "../qli/proc_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/utl_proto.h"
#include "../jrd/gdsassert.h"
#include "../common/utils_proto.h"
#include "../common/classes/TempFile.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@ -59,11 +59,7 @@ const SLONG LIB$_INPSTRTRU = 0x15821c;
#include <io.h> // isatty
#endif
#ifdef SMALL_FILE_NAMES
static const char* SCRATCH = "fb_q";
#else
static const char* SCRATCH = "fb_query_";
#endif
const char* FOPEN_INPUT_TYPE = "r";
@ -160,17 +156,16 @@ void LEX_edit( SLONG start, SLONG stop)
* push the scratch file on the input stack.
*
**************************************/
TEXT filename[MAXPATHLEN];
FILE* scratch = (FILE*) gds__temp_file(TRUE, SCRATCH, filename);
if (scratch == (FILE *) - 1)
const Firebird::PathName filename = TempFile::create(SCRATCH);
FILE* scratch = fopen(filename.c_str(), "w+b");
if (scratch == (FILE *) -1)
IBERROR(61); // Msg 61 couldn't open scratch file
#ifdef WIN_NT
stop--;
#endif
if (fseek(trace_file, start, 0)) {
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
IBERROR(59); // Msg 59 fseek failed
}
@ -183,12 +178,12 @@ void LEX_edit( SLONG start, SLONG stop)
fclose(scratch);
if (gds__edit(filename, TRUE))
LEX_push_file(filename, true);
if (gds__edit(filename.c_str(), TRUE))
LEX_push_file(filename.c_str(), true);
unlink(filename);
unlink(filename.c_str());
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
}
@ -352,7 +347,7 @@ void LEX_fini(void)
*
**************************************/
if (trace_file && (trace_file != (FILE *) - 1)) {
if (trace_file) {
fclose(trace_file);
unlink(trace_file_name);
}
@ -545,8 +540,10 @@ void LEX_init(void)
* scratch trace file to keep all input.
*
**************************************/
trace_file = (FILE*) gds__temp_file(TRUE, SCRATCH, trace_file_name);
if (trace_file == (FILE *) - 1)
const Firebird::PathName filename = TempFile::create(SCRATCH);
strcpy(trace_file_name, filename.c_str());
trace_file = fopen(trace_file_name, "w+b");
if (trace_file == (FILE *) -1)
IBERROR(61); // Msg 61 couldn't open scratch file
QLI_token = (qli_tok*) ALLOCPV(type_tok, MAXSYMLEN);
@ -726,7 +723,7 @@ void LEX_put_procedure(FB_API_HANDLE blob, SLONG start, SLONG stop)
ISC_STATUS_ARRAY status_vector;
if (fseek(trace_file, start, 0)) {
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
IBERROR(62); // Msg 62 fseek failed
}
@ -756,7 +753,7 @@ void LEX_put_procedure(FB_API_HANDLE blob, SLONG start, SLONG stop)
ERRQ_bugcheck(58); // Msg 58 isc_put_segment failed
}
fseek(trace_file, (SLONG) 0, 2);
fseek(trace_file, 0, 2);
}